]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
-Wdangling-pointer: don't mark SSA lhs sets as stores
authorAlexandre Oliva <oliva@adacore.com>
Fri, 3 Mar 2023 18:59:30 +0000 (15:59 -0300)
committerAlexandre Oliva <oliva@gnu.org>
Fri, 3 Mar 2023 18:59:30 +0000 (15:59 -0300)
check_dangling_stores has some weirdnesses that causes its behavior to
change when the target ABI requires C++ ctors to return this: while
scanning stmts backwards in e.g. the AS ctor on a target that returns
this in ctors, the scan first encounters a copy of this to the SSA
name used to hold the return value.  m_ptr_query.get_ref resolves lhs
(the return SSA name) to the rhs (the default SSA name for this), does
not skip it because auto_var_p is false for SSA_NAMEs, and proceeds to
add it to stores, which seems to prevent later attempts to add stores
into *this from succeeding, which disables warnings that should have
triggered.

This is also the case when the backwards search finds unrelated stores
to other fields of *this before it reaches stores that IMHO should be
warned about.  The store found first disables checking of other
stores, as if the store appearing later in the code would necessarily
overwrite the store that should be warned about.  I've added an
xfailed variant of the existing test (struct An) that triggers this
problem, but I'm not sure how to go about fixing it.

Meanwhile, this patch prevents assignments with SSA_NAMEs in the lhs
from being regarded as stores, which is enough to remove the
undesirable side effect on -Wdangling-pointer of ABI-mandated ctors'
returning this.  Another variant of the existing test (struct Al) that
demonstrates the problem regardless of this aspect of the ABI, and
that gets the desired warning with the proposed patch, but not
without.

Curiously, this fix exposes yet another problem in
Wdangling-pointer-5.c: it is the return stmt of the unrelated pointer
p, not the store into possibly-overlapping *vpp2, that caused the
warning to not be issued for the store in *vpp1.  I'm not sure whether
we should or should not warn in that case, but this patch adjusts the
test to reflect the behavior change.

for  gcc/ChangeLog

* gimple-ssa-warn-access.cc
(pass_waccess::check_dangling_stores): Skip non-stores.

for  gcc/testsuite/ChangeLog

* g++.dg/warn/Wdangling-pointer.C (warn_init_ref_member): Add
two new variants, one fixed, one xfailed.
* c-c++-common/Wdangling-pointer-5.c
(nowarn_store_arg_store_arg): Add now-expected warnings.

gcc/gimple-ssa-warn-access.cc
gcc/testsuite/c-c++-common/Wdangling-pointer-5.c
gcc/testsuite/g++.dg/warn/Wdangling-pointer.C

index a28fce172b5f9af6d19b15298aa3f63539219cf1..8b1c1cc019e3a52ea09fb5d3c15628f05c38589b 100644 (file)
@@ -4515,7 +4515,8 @@ pass_waccess::check_dangling_stores (basic_block bb,
           use the escaped locals.  */
        return;
 
-      if (!is_gimple_assign (stmt) || gimple_clobber_p (stmt))
+      if (!is_gimple_assign (stmt) || gimple_clobber_p (stmt)
+         || !gimple_store_p (stmt))
        continue;
 
       access_ref lhs_ref;
index 2a165cea767688a03e6ed38f772f5fa09384072b..cb6da9e86394d575bb21299daa42ac649e6833c3 100644 (file)
@@ -75,9 +75,9 @@ void nowarn_store_arg_store (void **vpp)
 
 void* nowarn_store_arg_store_arg (void **vpp1, void **vpp2)
 {
-  int x;
+  int x;              // { dg-message "'x' declared here" }
   void **p = (void**)sink (0);
-  *vpp1 = &x;         // warn here?
+  *vpp1 = &x;         // { dg-warning "storing the address of local variable 'x' in '\\*vpp1'" }
   *vpp2 = 0;          // might overwrite *vpp1
   return p;
 }
index 22c559e4adafea3e6c86b31c78258be9c092138c..a94477a6476660db80920650c78fc90c1ffcf233 100644 (file)
@@ -35,7 +35,34 @@ void warn_init_ref_member ()
     { }
   } ai;
 
-  sink (&as, &ai);
+  struct Al
+  {
+    const S &sref;
+    Al ():
+      // The temporary S object is destroyed when Al::Al() returns.
+      sref (S ())  // { dg-warning "storing the address" }
+    {
+      // Copying this to an SSA_NAME used to disable the warning:
+      Al *ptr = this;
+      asm ("" : "+r" (ptr));
+    }
+  } al;
+
+  struct An
+  {
+    An *next;
+    const S &sref;
+    An ():
+      next (0),
+      // The temporary S object is destroyed when An::An() returns.
+      sref (S ())  // { dg-warning "storing the address" "" { xfail *-*-* } }
+    {
+      // ??? Writing to another part of *this disables the warning:
+      next = 0;
+    }
+  } an;
+
+  sink (&as, &ai, &al, &an);
 }