Live data from Hacker News

Stop Memsetting Structures

anmolsarma.in

31–40 of 277 posts

Re: Stop Memsetting Structures

#31
This is mostly a matter of taste, but if the first example makes sense, the second example looks less clear, because, for someone quickly skimming through the code, a variable which have a somewhat clear meaning "yes" (that could be improved) is replaced with a magic number who have no intrinsic meaning.

Re: Stop Memsetting Structures

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

>NULL != (void* )0.

This expression is false in any C99 compliant system:

Section 6.3.2.3 [0]:

> An integer constant expression with the value 0, or such an expression cast to type void * , is called a null pointer constant. [1] If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function

> Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.

The technicality of the memset example is that it does not set the bits of the pointer by referring to it as a pointer, so the requirement that 0 behave as if it was a null pointer does not apply.

[0] http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf

[1] In text footnote: The macro NULL is defined in (and other headers) as a null pointer constant; see 7.17

EDIT: Formatting

Re: Stop Memsetting Structures

#33
post #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.

Surely you only need memset_s if you're doing this for security reasons, as if memset is optimized away it's because the compiler can prove the observable semantics are the same.

Re: Stop Memsetting Structures

#34
Because it’s 2019!

It really irritates me when people give arguments like this. I seriously don't care what year it is, I care that the code I write works. A lot of projects still use C89 because they want the widest portability. C99 isn't very new, but especially in the embedded and other niche industries, C89 (often with some extensions) is all you get.

That said, "= { 0 };" is almost always usable instead of a memset() and works in C89 too.

And finally, there is absolutely no reason to check if a pointer is NULL just before calling free() on it

This is advice I agree with. The nullcheck is in free() itself (IMHO a good design decision --- especially along error-handling and cleanup paths.)

Re: Stop Memsetting Structures

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

[deleted]

Re: Stop Memsetting Structures

#36
post #31

This is mostly a matter of taste, but if the first example makes sense, the second example looks less clear, because, for someone quickly skimming through the code, a variable which have a somewhat clear meaning "yes" (that could be improved) is replaced with a magic number who have no intrinsic meaning.

I agree. I’m also not a fan of doing `sizeof(typename)` as it can hide intent

Re: Stop Memsetting Structures

#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?

Re: Stop Memsetting Structures

#39
post #12

Earlier quoted context omitted.

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?

Tbh I'm not a network person, but my naive brain says instead of casting to char* and writing to the buffer, couldn't you just write out individual fields to a buffer so you control every byte? That seems smarter and safer.

Re: Stop Memsetting Structures

#40
> Elements that are not specified are initialized as if they are static objects: arithmetic types are initialized to 0; pointers are initialized to NULL.

That's actually not true. It is the case when initializing arrays, but for structs (and unions) any non-named member has "indeterminate value" (see paragraph 9, section 6.7.8 of ISO/IEC 9899:1999; unchanged in C11 and C18). Well, at least according to the standard - GCC, Clang and MSVC all happen to make it zero, but it's not guaranteed by the C language.

The trick with avoiding a variable when passing an address to a literal value is nice though, I didn't know that. There are some places in my code that could use it ;)

Post reply on HN