https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104069
Martin Sebor <msebor at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |amacleod at redhat dot com --- Comment #6 from Martin Sebor <msebor at gcc dot gnu.org> --- Thanks. The new test case can be reduced to this: void *xrealloc (void *ptr, int size) { void *ret = __builtin_realloc (ptr, size); if (!ret && !size) ret = __builtin_realloc (ptr, 1); if (!ret) { ret = __builtin_realloc (ptr, size); <<< -Wuse-after-free if (!ret && !size) ret = __builtin_realloc(ptr, 1); <<< -Wuse-after-free if (!ret) __builtin_abort (); } return ret; } I don't see a bug in the warning code but let me CC Andrew for his comments on the Ranger behavior. The warnings are false positives but I'm afraid I don't see a bug in the implementation. Both trigger (at level 2) because the code is unable to rule out that the successfully reallocated pointer isn't used in a subsequent call to realloc(). In the unptimized IL the annotated flow for the first warning is below. It shows that the realloc(ptr) statement in bb 8 isn't reachable with a nonnull ret_13 (i.e., after a successful call to realloc(ptr) in bb 2) but the range query for the value of ret_13 in bb 8 returns an unknown (i.e., either null or nonnull). Andrew, this is determined by the following test art gimple-ssa-warn-access.cc:4152: if (m_ptr_qry.rvals->range_of_expr (vr, realloc_lhs, use_stmt)) realloc_lhs is ret_13 and use_stmt is ret_19 = __builtin_realloc (ptr_11(D), 1). debug_ranger() shows that bb 5 exports ret_3 == 0 but not ret_13 (which is implied by the ret_3 equality to zero). Is this a limitation I need to be prepared for? void * xrealloc (void * ptr, int size) { void * ret; void * D.1996; long unsigned int _1; long unsigned int _2; void * _21; <bb 2> : _1 = (long unsigned int) size_9(D); ret_13 = __builtin_realloc (ptr_11(D), _1); if (ret_13 == 0B) goto <bb 3>; [INV] >>> ret_13 == 0 else goto <bb 5>; [INV] >>> ret_13 != 0 <bb 3> : if (size_9(D) == 0) goto <bb 4>; [INV] else goto <bb 5>; [INV] <bb 4> : ret_15 = __builtin_realloc (ptr_11(D), 1); <<< ret_13 == 0 <bb 5> : # ret_3 = PHI <ret_13(2), ret_13(3), ret_15(4)> if (ret_3 == 0B) goto <bb 6>; [INV] >>> ret_13 == 0 && ret_3 == 0 else goto <bb 11>; [INV] <bb 6> : _2 = (long unsigned int) size_9(D); ret_17 = __builtin_realloc (ptr_11(D), _2); if (ret_17 == 0B) goto <bb 7>; [INV] >>> ret_13 == 0 && ret_3 == 0 && ret_17 == 0 else goto <bb 9>; [INV] <bb 7> : if (size_9(D) == 0) goto <bb 8>; [INV] >>> ret_13 == 0 && ret_3 == 0 && ret_17 == 0 && size_9 == 0 else goto <bb 9>; [INV] <bb 8> : <<< ret_13 need not be 0 here ret_19 = __builtin_realloc (ptr_11(D), 1); <<< -Wuse-after-free <bb 9> : # ret_4 = PHI <ret_17(6), ret_17(7), ret_19(8)> if (ret_4 == 0B) goto <bb 10>; [INV] else goto <bb 11>; [INV] <bb 10> : __builtin_abort (); <bb 11> : # ret_5 = PHI <ret_3(5), ret_4(9)> _21 = ret_5; <bb 12> : <L12>: return _21; } In the optimized IL (at -O2 below), it looks like the same issue. Again, the IL makes it clear that the call to realloc(ptr) in bb 5 where the warning triggers isn't reachable after a successful prior realloc(), void * xrealloc (void * ptr, int size) { void * ret; long unsigned int _1; _Bool _2; _Bool _3; _Bool _4; _Bool _5; _Bool _6; <bb 2> [local count: 1073741824]: _1 = (long unsigned int) size_13(D); ret_17 = __builtin_realloc (ptr_15(D), _1); _2 = ret_17 == 0B; _3 = size_13(D) == 0; _4 = _2 & _3; if (_4 != 0) goto <bb 3>; [33.00%] >>> ret_17 == 0 else goto <bb 4>; [67.00%] >>> ret_17 need not be 0 <bb 3> [local count: 354334800]: ret_19 = __builtin_realloc (ptr_15(D), 1); <bb 4> [local count: 1073741824]: # ret_7 = PHI <ret_17(2), ret_19(3)> if (ret_7 == 0B) goto <bb 5>; [0.04%] >>> ret_7 == 0 implies ret_17 == 0 else goto <bb 9>; [99.96%] <bb 5> [local count: 429496]: <<< ret_17 == 0 but query returns unknown ret_21 = __builtin_realloc (ptr_15(D), _1); <<< -Wuse-after-free