https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102731
Bug ID: 102731 Summary: inconsistent handling of dereferncing a null pointer Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- The test case below shows that GCC doesn't handle null pointer dereferences consistently or as helpfully as it could or should. Of the three equivalent functions, GCC only issues a warning pointing out the invalid access only for the first. For the other two it doesn't warn even though it clearly detects the invalid access and injects a trap after it. $ cat x.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout x.c struct A { char n, a[4]; }; void f (struct A *p) { if (p) return; __builtin_memset (p->a, 0, 4); // warning, no trap } void g (struct A *p) { if (p) return; p->a[0] = 0; // trap, no warning p->a[1] = 0; p->a[2] = 0; p->a[3] = 0; } void h (struct A *p) { if (p) return; for (int i = 0; i != 4; ++i) p->a[i] = 0; // trap, no warning } x.c: In function ‘f’: x.c:7:3: warning: ‘__builtin_memset’ offset [0, 3] is out of the bounds [0, 0] [-Warray-bounds] 7 | __builtin_memset (p->a, 0, 4); // warning, no trap | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;; Function f (f, funcdef_no=0, decl_uid=1981, cgraph_uid=1, symbol_order=0) Removing basic block 5 void f (struct A * p) { <bb 2> [local count: 1073741824]: if (p_3(D) != 0B) goto <bb 4>; [70.93%] else goto <bb 3>; [29.07%] <bb 3> [local count: 312136752]: __builtin_memset (1B, 0, 4); [tail call] <bb 4> [local count: 1073741824]: return; } ;; Function g (g, funcdef_no=1, decl_uid=1984, cgraph_uid=2, symbol_order=1) void g (struct A * p) { <bb 2> [local count: 1073741824]: if (p_2(D) != 0B) goto <bb 4>; [54.59%] else goto <bb 3>; [45.41%] <bb 3> [local count: 487586160]: MEM[(struct A *)0B].a[0] ={v} 0; __builtin_trap (); <bb 4> [local count: 1073741824]: return; } ;; Function h (h, funcdef_no=2, decl_uid=1987, cgraph_uid=3, symbol_order=2) void h (struct A * p) { <bb 2> [local count: 472909864]: if (p_4(D) != 0B) goto <bb 4>; [54.59%] else goto <bb 3>; [45.41%] <bb 3> [local count: 214748368]: MEM[(struct A *)0B].a[0] ={v} 0; __builtin_trap (); <bb 4> [local count: 472909864]: return; }