Today's discovery: gcc will remove calls to memcpy() with a len of 0 (good), knows it's UB to call memcpy() with a dest of NULL (spec compliant), will assume that dest can't be NULL (fucking compilers, man), will combine both to engage in this UTTERLY ...
-
Today's discovery: gcc will remove calls to memcpy() with a len of 0 (good), knows it's UB to call memcpy() with a dest of NULL (spec compliant), will assume that dest can't be NULL (fucking compilers, man), will combine both to engage in this UTTERLY PATHOLOGICAL BEHAVIOUR https://godbolt.org/z/bGqM6arGT
-
This makes no sense. There is no way that the compiler will know the len is zero at compile time.
It could possibly be zero at runtime.
One must beat the compiler into submission.
-
@SpaceLifeForm It’s inlined.
-
I am confused then. I do not see how inlining the code prevents a problem that could occur at runtime.
-
@SpaceLifeForm The compiler can see the exact values passed and optimize for them. Ie the compiler can look for passing an obvious zero to memcpy, which it couldn’t do if it were just a variable passed across a translation unit boundary.
-
What if I wrote a safe_memcpy() function in a library?
And then did a Define to change all references to memcpy() to safe_memcpy() ?
Why should I trust the compiler to understand the semantics of safe_memcpy() ?
Remember, the safe_memcpy is in an extern lib.
Instead of compiler trying to be smart, the fix should be in the called function. I.E., memcpy() should be safe_memcpy() and not do stupid UB shit.
The called function should defend itself from bad inputs.
It should not be up to the compiler to defend the called function from bad input and bad code.
-
@SpaceLifeForm You are confused. Passing 0 is not UB; it can merely be optimized away. Passing NULL is UB, and in this case the compiler is using the fact that the pointer cannot safely be NULL to optimize subsequent code.
-
How does the compiler know that passing zero for the len is a waste of time?
How does the compiler know that passing NULL for a pointer is a problem?
Historical: In early C on 3B2 processors, NULL was defined as zero. At address zero, there was a zero.
A NULL ptr pointed to a null string.
I am not saying this was good, just how it was.
Which is why I wrote a bunch of safe versions in order to port K&R C to ANSI C (to port to other machines) because NULL was really NULL and not zero. The code would function on 3B2 but crash on different machines.