https://gcc.gnu.org/g:6345c1c11c2024d707ab1f8eb556a1eddd65dba0

commit r16-6531-g6345c1c11c2024d707ab1f8eb556a1eddd65dba0
Author: Siddhesh Poyarekar <[email protected]>
Date:   Tue Jan 6 10:21:50 2026 -0500

    warn_access: Limit waccess2 to dangling pointer checks [PR 123374]
    
    The second pass of warn_access (waccess2) was added to implement
    dangling pointer checks but it implicitly ran the early checks too,
    which issues false warnings on code that has not been fully optimized.
    
    Limit this second run to only dangling pointer checks for call
    statements.  This does not break any of the existing warning tests, so
    it didn't seem to add any actual value for the additional run anyway.
    
    gcc/ChangeLog:
    
            PR tree-optimization/123374
            * gimple-ssa-warn-access.cc (pass_waccess::set_pass_param): Add
            a second parameter.
            (pass_waccess::check_call): Skip access checks for waccess2.
            (pass_waccess::execute): Drop initialization of
            M_CHECK_DANGLING_P.
            * passes.def: Adjust.
    
    gcc/testsuite/ChangeLog:
    
            PR tree-optimization/123374
            * g++.dg/warn/pr123374.C: New test.
    
    Signed-off-by: Siddhesh Poyarekar <[email protected]>

Diff:
---
 gcc/gimple-ssa-warn-access.cc        | 38 +++++++++++++++++++++++-------------
 gcc/passes.def                       |  6 +++---
 gcc/testsuite/g++.dg/warn/pr123374.C | 32 ++++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 17 deletions(-)

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 44e62475cfa9..df34da2bf960 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -2246,11 +2246,21 @@ pass_waccess::~pass_waccess ()
 }
 
 void
-pass_waccess::set_pass_param (unsigned int n, bool early)
+pass_waccess::set_pass_param (unsigned int n, bool param)
 {
-  gcc_assert (n == 0);
-
-  m_early_checks_p = early;
+  /* Check for dangling pointers in the earliest runs of the pass.
+     The latest point -Wdangling-pointer should run is just before
+     loop unrolling which introduces uses after clobbers.  Most cases
+     can be detected without optimization; cases where the address of
+     the local variable is passed to and then returned from a user-
+     defined function before its lifetime ends and the returned pointer
+     becomes dangling depend on inlining.  */
+  if (n == 0)
+    m_early_checks_p = param;
+  else if (n == 1)
+    m_check_dangling_p = param;
+  else
+    __builtin_unreachable ();
 }
 
 /* Return true when any checks performed by the pass are enabled.  */
@@ -4380,6 +4390,16 @@ pass_waccess::check_call (gcall *stmt)
       && gimple_call_internal_fn (stmt) == IFN_ASAN_MARK)
     return;
 
+  if (m_check_dangling_p)
+    {
+      check_call_dangling (stmt);
+
+      /* Don't do any other checks when doing dangling pointer checks the
+        second time.  */
+      if (!m_early_checks_p)
+       return;
+    }
+
   if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
     check_builtin (stmt);
 
@@ -4397,7 +4417,6 @@ pass_waccess::check_call (gcall *stmt)
     }
 
   check_call_access (stmt);
-  check_call_dangling (stmt);
 
   if (m_early_checks_p)
     return;
@@ -4800,15 +4819,6 @@ pass_waccess::execute (function *fun)
   m_ptr_qry.rvals = enable_ranger (fun);
   m_func = fun;
 
-  /* Check for dangling pointers in the earliest run of the pass.
-     The latest point -Wdangling-pointer should run is just before
-     loop unrolling which introduces uses after clobbers.  Most cases
-     can be detected without optimization; cases where the address of
-     the local variable is passed to and then returned from a user-
-     defined function before its lifetime ends and the returned pointer
-     becomes dangling depend on inlining.  */
-  m_check_dangling_p = m_early_checks_p;
-
   auto_bitmap bb_uids_set (&bitmap_default_obstack);
   m_bb_uids_set = bb_uids_set;
 
diff --git a/gcc/passes.def b/gcc/passes.def
index 54b56b3c0c8d..4586d2cf6ad7 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -61,7 +61,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_warn_printf);
       NEXT_PASS (pass_warn_nonnull_compare);
       NEXT_PASS (pass_early_warn_uninitialized);
-      NEXT_PASS (pass_warn_access, /*early=*/true);
+      NEXT_PASS (pass_warn_access, /*early=*/true, /*check_dangling=*/true);
       NEXT_PASS (pass_ubsan);
       NEXT_PASS (pass_nothrow);
       NEXT_PASS (pass_rebuild_cgraph_edges);
@@ -216,7 +216,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_object_sizes);
       NEXT_PASS (pass_post_ipa_warn);
       /* Must run before loop unrolling.  */
-      NEXT_PASS (pass_warn_access, /*early=*/true);
+      NEXT_PASS (pass_warn_access, /*early=*/false, /*check_dangling=*/true);
       /* Profile count may overflow as a result of inlinining very large
          loop nests.  This pass should run before any late pass that makes
         use of profile.  */
@@ -451,7 +451,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_gimple_isel);
   NEXT_PASS (pass_harden_conditional_branches);
   NEXT_PASS (pass_harden_compares);
-  NEXT_PASS (pass_warn_access, /*early=*/false);
+  NEXT_PASS (pass_warn_access, /*early=*/false, /*check_dangling=*/false);
   NEXT_PASS (pass_cleanup_cfg_post_optimizing);
   NEXT_PASS (pass_warn_function_noreturn);
 
diff --git a/gcc/testsuite/g++.dg/warn/pr123374.C 
b/gcc/testsuite/g++.dg/warn/pr123374.C
new file mode 100644
index 000000000000..d451f57cc919
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/pr123374.C
@@ -0,0 +1,32 @@
+// { dg-do compile }
+// { dg-additional-options "-O2 -Wstringop-overflow" }
+
+long ext_f (void *, unsigned long)
+    __attribute__ ((__access__ (__write_only__, 1, 2)));
+
+long f (void *b, unsigned long n)
+{
+  unsigned long sz = __builtin_dynamic_object_size(b, 0);
+
+  return (__builtin_constant_p (sz) && sz == -1UL) ? ext_f (b, n) : 0;
+}
+
+
+void test (unsigned limit, long init_off)
+{
+  char buf[4096];
+  unsigned long off = 0;
+
+  while (off == 0)
+    off += init_off;
+
+  while (off < limit)
+    {
+      long n = f (buf + off, sizeof (buf) - off);
+
+      if (n <= 0)
+       continue;
+
+      off += n;
+    }
+}

Reply via email to