https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93156
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jakub at gcc dot gnu.org --- Comment #9 from Jakub Jelinek <jakub at gcc dot gnu.org> --- (In reply to Bruno Haible from comment #8) > (In reply to Andrew Pinski from comment #6) > > a?-1:0 is transformed into -1 before we figure out that a is always true; an > > ordering difference. > > Fortunately the GCC optimization affects only the return value of > null_ptr(). It does not cause side effects to occur that shouldn't occur. > > Test case: > ========================================================================= > extern char *canonicalize_file_name (const char *__name) > __attribute__ ((__nonnull__ (1))); > extern int rand (void); > extern void brick_the_hard_disk (void); > > /* Return NULL. */ > static void * > null_ptr (void) > { > unsigned int x = rand (); > unsigned int y = x * x; > /* The following statement is equivalent to if (false), > since a square is always congruent to 0 or 1 mod 4. */ > if (y & 2) { > brick_the_hard_disk (); > return (void *) -1; > } else > return (void *) 0; > } > > int > main (void) > { > return !!canonicalize_file_name (null_ptr ()); > } An optimizing compiler optimizes the assumption that UB doesn't occur, because when it occurs, anything can happen. The above testcase has an unconditional UB when passing NULL to function argument that requires NULL is not passed to it and thus the compiler when seeing that a value outside the range [(void *)1, (void *) -2] (i.e. either NULL or (void *) -1) is passed to it and the requirement for nonnull is that it is not NULL figures out that the range must be [(void *) -1, (void *) -1] and replaces it with the constant all ones pointer. If say y & 4 was used instead of y & 2, the UB would be only conditional, and in any case, the compiler can't call brick_the_hard_disk before reaching the UB, but once invoking UB, it can call anything, format the disk in other ways and perform anything else. So the only thing we should take from the above for the compiler is optimize in ccp that x*x has the second least significant bit clear. Will handle that today.