The current -fdelete_null_pointer_checks implementation makes assumptions that the target processor will trap on reads or writes to address zero. Unfortunately, these assumptions are target (often operating system) specific. Here's a test case for AIX: void abort(); int test(char *ptr) { int x = *ptr; return ptr ? x+1: 2; } int main() { if(test(0) != 2) abort(); } When compiled with mainline this aborts when compiled at -O2 or higher, and passes when compiled at -O1 or lower. AIX allows reads from but not writes to address zero. Other targets, specifically those without virtual memory often allow both reading and writing to address zero. I propose we should add target macros, TARGET_NULL_POINTER_READABLE and TARGET_NULL_POINTER_WRITABLE and control the effects of the -fdelete_null_pointer_checks with that. The current situation is that these transformations are enabled automatically at -O2 without regard to the target environment.
Apparently the behaviour of this code is undefined in the C/C++ language standards, though this transformation is performed in front-end independent code. Perhaps its only a quality of implementation issue.
Note the flag is old, it comes from: Thu Sep 23 13:55:21 1999 Jeffrey A Law (law@cygnus.com) * invoke.texi: Document -fdelete-null-pointer-checks * toplev.c (flag_delete_null_pointer_checks): New. (f_options): Add entry for -fdelete-null-pointer-checks. (rest_of_compilation): Conditionalize null pointer check elimination on flag_delete_null_pointer_checks. (main): If -O2 or greater, enable -fdelete-null-pointer-checks
(In reply to comment #0) > The current -fdelete_null_pointer_checks implementation makes assumptions that > the target processor will trap on reads or writes to address zero. Unfortunately, > these assumptions are target (often operating system) specific. > ... > I propose we should add target macros, TARGET_NULL_POINTER_READABLE and > TARGET_NULL_POINTER_WRITABLE and control the effects of the > -fdelete_null_pointer_checks with that. The current situation is that > these transformations are enabled automatically at -O2 without regard to > the target environment. Correct, and as coppied from PR21479: > > "a null reference is undefined" => "may trap" => "will trap" > > is simply wrong, and is not justifyable; such an optimization > > is target specific, as it depends on "will trap" target semantics. > > Right. However, the logic here is simply "a null pointer dereference is > undefined" => "if you still do it, your code may behave however gcc feels > like", which is backed by the C standard. So this is invalid. No, only the "null pointer dereference" itself is undefined. which means that upon a null pointer reference any or no value may be returned. Is says, implies, and grants no rights what so ever to an implementation, to define that an arbitrary behavior will occure which may be subsequenlty relied upon to occure unless the implementation inforces that behavior. More specifically, unless GCC can warrent that a "null pointer dereference" will trap will terminate program execution, it must preserve the semantics of the remaining programs execution as defined by the standard, which includes but not limited to preserving null-pointer comparision semantics, as defined by the standard; as not to do so would be in violation of the same. ("If -O2 or greater, enable -fdelete-null-pointer-checks" can not be unconditionally enabled without violating the semantics of the language.)
6.5.3.2/4 says that the behavior unary * operator is undefined if the pointer is a null pointer. For QOI reasons several targets / frontends have -fdelete-null-pointer-checks disabled.