Re:Undefined behavior in C is a reading error
by tom_mellior on Thursday May 20, 2021 @05:36PM
(#27227630)
This was in the Linux kernel, which is compiled with special kernel flags which make dereferencing null pointers legal. In the context of that code, dereferencing a pointer and later checking it for null was absoutely meaningful. Optimizing the later null check was a compiler bug that was acknowledged and fixed. The compiler here didn't respect the semantics it had promised to kernel code. This was entirely uncontroversial; it was not a case of "unwanted optimization based on undefined behavior", it was a case of "compiler bug breaking well-defined code". Again, all this in a kernel context.
In user code GCC will still happily remove the null check because in user code this is an actual bug in the user's code.
Re:Undefined behavior in C is a reading error
by a1369209993 on Thursday May 20, 2021 @10:02PM
(#27229728)
Actually, there's a even worse version:
struct foo { ...; bar_t bar[NBAR]; };
struct foo* p = ...;
bar_t* q = &p->bar[0]; // add rq, rp, #foo_bar_offs
// other declarations
if(!p) return NOPE; // optimized out
// use p and q
Not even any dereferencing, just pointer arithmetic.
Re:Undefined behavior in C is a reading error
by tom_mellior on Friday May 21, 2021 @03:49PM
(#27239036)
Could you post a complete example please and tell us which compiler optimizes out this check? Clang and GCC don't: https://gcc.godbolt.org/z/dbTadEcra
Re:Undefined behavior in C is a reading error
by schlupa on Friday May 21, 2021 @01:48PM
(#27237403)
Yes, that one is especially nasty as &p->bar[0] is a constant expression completely solvable at compile time.
It's equivalent to the offsetof() macro of stddef.h
It had code like:
Then a later refactor wrongly added a single line before the if statement: This meant the null check was optimized away, since de referencing a null pointer is undefined behavior, so the if-statement can be assumed to be always false. This then lead to actual errors (perhaps even an exploit, I do not recall) arising from the removed null-check.I think in general the "sanity check" cases are the worst. It is hard to determine whether an expression causes undefined behavior if you cannot try and evaluate it. Perhaps a compiler intrinsic that checks (at runtime) whether an expression causes undefined behavior could be useful here. Though I can imagine such an intrinsic being essentially impossible to implement.