4 ms·
Please read the edit below. This case has a very subtly trap. ------ Old comment: Makes sense it's undefined behavior, because address 0 is involved. Although
by vardump 10y ago
Please read the edit below. This case has a very subtly trap.
------
Old comment:
Makes sense it's undefined behavior, because address 0 is involved. Although I'd guess compiler implementations might just drop whole statement, because length is 0.
Zero length memory copy is a no-op.
Just like static zero iteration loop. They become zero instructions. (Except of course initialization that affects something outside loop scope.)
Edit:
Changed my mind after learning about the tricky UB pathway: If compiler can statically prove memcpy length argument to be zero, it can ALSO prove both argument pointers to be not NULL!
Ouch!
- Rarebox 10y agomemcpy(0x1, 0x1, 0) is a well-defined no-op even when you don't have 0x1 in your address space. Why handle 0x0 differently?
- vardump 10y agoWell, just before I just saw a "read" and a "write" to address 0. Not as mechanism that can cause serious bugs, when the compiler can statically prove length argument to be 0 and you can have NULL arguments as input. Calls to memcpy with zero length are definitely not uncommon. Macros are an obvious way, but it's worse. All you need is a data flow where compiler can statically prove that all paths lead to zero length argument. I have to agree it's very scary that memcpy(NULL, NULL, 0) is undefined.
- plorkyeran 10y agoPassing a non-null pointer that points outside your address space is made UB by the exact same sentence as the one that makes passing null UB.
- quotemstr 10y ago> memcpy(0x1, 0x1, 0) is a well-defined no-op Sure about that? It really should be a no-op. The C and C++ standards are seriously broken in this respect, and compiler authors take advantage of this brokenness to get away with miscompiling programs that, to anyone with common sense, are fine.
- quotemstr 10y agoIt makes absolutely no sense for this behavior to be undefined, and letting it be undefined behavior causes real problems. See https://www.imperialviolet.org/2016/06/26/nonnull.html https://www.imperialviolet.org/2016/06/26/nonnull.html The C and C++ standards must be changed to explicitly state that memory operations on zero bytes do nothing regardless of whether the inputs are valid pointers.
- vardump 10y agoOuch. Didn't think about that compilers can then assume passed pointers aren't NULL. And proceed to optimize your NULL checks away, because that memcpy would have been undefined behavior. It seems so obvious after reading that. Should always ask oneself "what can the compiler prove as a consequence of this undefined behavior?". So, you're right, memcpy(NULL, NULL, 0) should be defined as a no-op.
- quotemstr 10y agoSome of us been trying to highlight for a long time now how compilers are taking unjustifiable liberties with undefined behavior
- vardump 10y agoWell, undefined behavior is generally a good thing. It enables a lot of very reasonable optimizations. Zero-length memcpy pathway to UB is not obvious, because whether the whole thing is UB depends on whether compiler can statically prove the length to be zero. Ugh.
- quotemstr 10y agoI think the statically-prove-length-is-zero thing is a distraction. What do you think of memcpy(ptr1, ptr2, 1)? The compiler should be able to assume (legitimately, this time) that ptr1 and ptr2 are non-null. The problem isn't a special case for zero length: the problem is the lack of a special case for zero length.