Live data from Hacker News

Stop Memsetting Structures

anmolsarma.in

41–50 of 277 posts

Re: Stop Memsetting Structures

#41
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…

Please explain how you send a struct over the network without UB and leaking the padding.

Re: Stop Memsetting Structures

#42
post #29

Earlier quoted context omitted.

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.

I feel like you're missing the point (the gcc -O0 was there for a reason) but I updated it. Is this better?

Re: Stop Memsetting Structures

#43
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.

The literal `0` is guaranteed to be the null pointer value when used as a pointer, so by definition

    NULL == (void*)0.
But given

    void *p = 0; 
    intptr_t i = 0;
it is not guaranteed that `memcmp(&i, &p, sizeof(p)) == 0`.

Re: Stop Memsetting Structures

#44

Am I the only one who finds this int yes=1; setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes)) ; much cleaner than this setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &(int) {1}, sizeof(int)); ?

No, you are not the only one.

The author of that code is trying to make it explicit -- "yes, I want to allow reuse of local addressses". Some will prefer this, some won't.

I personally like the use of the variable, though I think it's not worth getting all bent out of shape about it one way or another. But I guess we all have our pet peeves, and I know I'm guilty of getting all bent out of shape about things that ultimately don't matter much.

Re: Stop Memsetting Structures

#45
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…

I am aware of the fact that unitilized padding can have nasty side effects: https://lwn.net/Articles/417989/

But yeah, I should have mentioned the caveats too. I will update the post once I'm back at my computer.

Re: Stop Memsetting Structures

#47
post #41
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…

Please explain how you send a struct over the network without UB and leaking the padding.

By knowing its exact size with sizeof(), and using that and a cast to uint8_t* to both bzero() it out before use and memcpy()ing it when sending it. Unless the C standard says that the compiler may change the padding bytes of the existing storage?

Re: Stop Memsetting Structures

#48
post #45

Earlier quoted context omitted.

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…

I am aware of the fact that unitilized padding can have nasty side effects: https://lwn.net/Articles/417989/ But yeah, I should have mentioned the caveats too. I will update the post once I'm back at my computer.

I'm confused what I'm supposed to look for in that article (do you mean you were the author?) but anyway -- I feel like calling this merely a "caveat" gives the wrong impression? It seems a bit like telling people to mix bleach with vinegar and then saying "Oops, sorry, I did know that it produces chlorine! I forgot to mention that caveat." The caveat isn't just a side note for the margins, it's a critical reason why people avoid this sort of thing.

Re: Stop Memsetting Structures

#49
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.

So if you're zeroing out a struct like so

  struct S {size_t a, void *p;};

  foo = (struct S) {0};
Does the standard require the compiler to set any pointers to NULL, or will everything be implicitly zeroed leaving pointers possibly improperly initialized to NULL?

Re: Stop Memsetting Structures

#50
post #37

Am I the only one who finds this int yes=1; setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes)) ; much cleaner than this setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &(int) {1}, sizeof(int)); ?

I agree anything is better than a magic number, but really only if the variable is properly descriptive. What are we saying 'yes' to?

Definitely agree that calling it `reuse_local` makes more sense, but OP was just quoting the blogpost.
Post reply on HN