Live data from Hacker News

Stop Memsetting Structures

anmolsarma.in

21–30 of 277 posts

Re: Stop Memsetting Structures

#21
post #12
post #2

Does that also zero the padding that may exist between elements of the structure (or at its end)? Because if not, not memset'ing will open you up to all kinds of info leaks, especially if you plan to send that struct over the network (or to another process, or from kernel to userspace...). EDIT: Actually I have to apologize, because I’m not certain what the C standard says about whether the padding bytes can change w…

Sending structures that include padding or that you don’t know the exact layout of over the network is another thing you shouldn’t do, period. Code doing that may break with a compiler change or a compilation flag change on one end of the connection, even if you can guarantee both ends use the same CPU.

> Sending structures that include padding or that you don’t know the exact layout of over the network is another thing you shouldn’t do, period.

What if you do know the exact layout and it happens to have a gap between fields?

Re: Stop Memsetting Structures

#22

C99 designated init doesn't work for C code that also needs to compile in C++ mode (...yet, a limited subset of designated init is coming in C++20, clang also seems to be more relaxed about this and allows the full C99 designated init also in C++ right now). For code that only needs to compile as C, I agree. It's one of the best (if not the best addition) to the C language. A nice addition would be default values for…

My C++ is rusty (no pun intended), but if your code also has to compile as C++, I think this will work instead of memset:

  struct addrinfo hints = {0};
If C++ requires

  struct addrinfo hints = {};
instead, you could create a macro, and write

  struct addrinfo hints = ALL_ZEROES;

Re: Stop Memsetting Structures

#23
post #7

Another reason to not memset structures: In the code struct foo { void * bar; } baz; ... memset(&baz, 0, sizeof(struct foo)); assert(baz.bar == NULL); it's possible for the assertion to fail, since NULL it not guaranteed to be represented in memory by a zero bytes.

> it's possible for the assertion to fail, since NULL it not guaranteed to be represented in memory by a zero bytes.

Technically correct (which is of course the best kind of correct) but you'd be hard pressed to find a system in 2019 where NULL != (void*)0. The most recent machines with non-zero NULL in the C FAQ entry on the matter (http://c-faq.com/null/machexamp.html) date back to the mid '90s.

Re: Stop Memsetting Structures

#24
post #12
post #2

Does that also zero the padding that may exist between elements of the structure (or at its end)? Because if not, not memset'ing will open you up to all kinds of info leaks, especially if you plan to send that struct over the network (or to another process, or from kernel to userspace...). EDIT: Actually I have to apologize, because I’m not certain what the C standard says about whether the padding bytes can change w…

Sending structures that include padding or that you don’t know the exact layout of over the network is another thing you shouldn’t do, period. Code doing that may break with a compiler change or a compilation flag change on one end of the connection, even if you can guarantee both ends use the same CPU.

Changing compiler or flags won't change structs, unless you do something crazy. If it did, you couldn't link C libraries compiled with one compiler with programs compiled on another.

You can't be sure you can send such structures to different OSes or CPUs however.

Re: Stop Memsetting Structures

#25
post #12
post #2

Does that also zero the padding that may exist between elements of the structure (or at its end)? Because if not, not memset'ing will open you up to all kinds of info leaks, especially if you plan to send that struct over the network (or to another process, or from kernel to userspace...). EDIT: Actually I have to apologize, because I’m not certain what the C standard says about whether the padding bytes can change w…

Sending structures that include padding or that you don’t know the exact layout of over the network is another thing you shouldn’t do, period. Code doing that may break with a compiler change or a compilation flag change on one end of the connection, even if you can guarantee both ends use the same CPU.

There is an attribute that lets you specify alignment per-struct, which means you will know the exact layout.

Re: Stop Memsetting Structures

#26
If you only use super simple structures maybe. It is quite common to zero out a structure and use only parts of it. It is also quite common to have to pragmatically fill in the structure.

Re: Stop Memsetting Structures

#27
My favourite trick with designated initialisers is using them with array indices and enums, e.g.

  enum color {RED, GREEN, BLUE};
  char *color_name[] = {
    [RED] = "Red",
    [GREEN] = "Green",
    [BLUE] = "Blue"
  };

  printf("%s",color_name[RED]);
This means you don't have to ensure ordering is the same between the enum and the array, which can be a pain for more complex tables. It's a shame C++ doesn't support this, more details: https://eli.thegreenplace.net/2011/02/15/array-initializatio...

Re: Stop Memsetting Structures

#28
post #7

Another reason to not memset structures: In the code struct foo { void * bar; } baz; ... memset(&baz, 0, sizeof(struct foo)); assert(baz.bar == NULL); it's possible for the assertion to fail, since NULL it not guaranteed to be represented in memory by a zero bytes.

> it's possible for the assertion to fail, since NULL it not guaranteed to be represented in memory by a zero bytes. Technically correct (which is of course the best kind of correct) but you'd be hard pressed to find a system in 2019 where NULL != (void*)0. The most recent machines with non-zero NULL in the C FAQ entry on the matter ( http://c-faq.com/null/machexamp.html ) date back to the mid '90s.

> you'd be hard pressed to find a system in 2019 where NULL != (void *)0

You'd be hard pressed to find a system at any time where NULL is not equal to a compile-time constant zero. ;-)

Re: Stop Memsetting Structures

#29
post #2

Does that also zero the padding that may exist between elements of the structure (or at its end)? Because if not, not memset'ing will open you up to all kinds of info leaks, especially if you plan to send that struct over the network (or to another process, or from kernel to userspace...). EDIT: Actually I have to apologize, because I’m not certain what the C standard says about whether the padding bytes can change w…

Nope it doesn't: //GCC: -O0 //MSVC: /Od #include #include struct S { unsigned char x; int y; }; int f(int f) { S a; memset(&a, f, sizeof(a)); unsigned char y[2]; memcpy(&y, &a, sizeof(y)); return y[1]; } int g() { S a = { 1, 2 }; unsigned char y[2]; memcpy(&y, &a, sizeof(y)); return y[1]; } int main(int argc, char *argv[]) { f(0xDD); printf("%#x\n", g()); f(0xFF); printf("%#x\n", g()); } It definitely seems like the…

That doesn’t check whether that memset call writes 0xFF bytes in the padding.

The compiler could also determine that &a.x)[1] is undefined behavior in C (reading past the end of an object), and take advantage of that.

The way to check that is by disassembling the code, and even that doesn’t say what a C compiler should do, only what these particular compilers do.

Re: Stop Memsetting Structures

#30
Because of c spec idiocy it isn’t event sufficient to use memset anymore, you need to use memset_s.

But “stop memsetting” is clearly nonsense if you care about security.

Post reply on HN