When checking for use of a dangling pointer, use_after_inval_p only
checks to see if there's a direct path between the use and the exit
block and that there's a clobber in the way.  This is insufficient to
prove dangling pointer access since the basic premise of the use being
reachable from End Of Scope clobber is not tested.

If there's a straight, potentially failing path from use to the exit
block, add another test to make sure that the use block is actually
reachable from the invalidating block before warning.

gcc/ChangeLog:

        PR middle-end/110091
        PR middle-end/124141
        * gimple-ssa-warn-access.cc (can_reach_from): New function.
        (pass_waccess::use_after_inval_p): Use it.

gcc/testsuite/ChangeLog:

        PR middle-end/110091
        PR middle-end/124141
        * c-c++-common/Wdangling-pointer-pr110091.c: New test.

Signed-off-by: Siddhesh Poyarekar <[email protected]>
---
Changes from v1:
- Dropped stmt traversal since it's not needed for straight line code.
- Added a post-dominator check in can_reach_from to shortcut traversal.

Testing:

- No new regressions in x86_64, i686
- Sqlite test case in BZ #124141 builds without spurious
  -Wdangling-pointers warnings
- x86_64 bootstrap in progress.
- This leaves only unresolved false negatives for -Wdangling-pointer.

 gcc/gimple-ssa-warn-access.cc                 | 53 +++++++++++++++++--
 .../c-c++-common/Wdangling-pointer-pr110091.c | 40 ++++++++++++++
 2 files changed, 89 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wdangling-pointer-pr110091.c

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index c8f10cae32f..c440c7761f9 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3854,6 +3854,43 @@ pass_waccess::maybe_check_dealloc_call (gcall *call)
     }
 }
 
+/* Return true if there is a path from FROM to TO.  VISITED logs the basic
+   blocks that have been previously visited.  */
+
+static bool
+can_reach_from (basic_block from, basic_block to,
+               hash_set<basic_block> &visited)
+{
+  edge_iterator ei;
+  edge e;
+
+  /* Avoid walking through the CFG if we can.  */
+  if (dominated_by_p (CDI_POST_DOMINATORS, from, to))
+    return true;
+
+  /* Walk through each successor, focusing on unique, normal, forward
+     edges.  */
+  FOR_EACH_EDGE (e, ei, from->succs)
+    {
+      if (e->flags & (EDGE_EH | EDGE_ABNORMAL | EDGE_DFS_BACK))
+       continue;
+
+      if (visited.add (e->dest))
+       continue;
+
+      if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+       continue;
+
+      if (e->dest == to)
+       return true;
+
+      if (can_reach_from (e->dest, to, visited))
+       return true;
+    }
+
+  return false;
+}
+
 /* Return true if either USE_STMT's basic block (that of a pointer's use)
    is dominated by INVAL_STMT's (that of a pointer's invalidating statement,
    which is either a clobber or a deallocation call), or if they're in
@@ -3907,10 +3944,18 @@ pass_waccess::use_after_inval_p (gimple *inval_stmt, 
gimple *use_stmt,
          gsi = gsi_start_bb (bb);
        }
 
-      /* The use is one of a dangling pointer if a clobber of the variable
-        [the pointer points to] has not been found before the function exit
-        point.  */
-      return bb == EXIT_BLOCK_PTR_FOR_FN (cfun);
+      /* Clobber of the variable [the pointer points to] has not been found
+        before the function exit point.  If there's a path from INVAL_BB to
+        USE_BB, then this is an access through a dangling pointer.  */
+      if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
+       {
+         hash_set<basic_block> visited;
+         visited.add (inval_bb);
+         if (can_reach_from (inval_bb, use_bb, visited))
+           return true;
+       }
+
+      return false;
     }
 
   if (bitmap_set_bit (m_bb_uids_set, inval_bb->index))
diff --git a/gcc/testsuite/c-c++-common/Wdangling-pointer-pr110091.c 
b/gcc/testsuite/c-c++-common/Wdangling-pointer-pr110091.c
new file mode 100644
index 00000000000..c26077c54ad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wdangling-pointer-pr110091.c
@@ -0,0 +1,40 @@
+/* PR middle-end/pr110091, middle-end/pr124141: bogus -Wdangling-pointer
+   warning on known-unreachable code.
+   { dg-do compile }
+   { dg-options "-O2 -Wdangling-pointer" } */
+
+struct tEntry
+{
+    int value;
+};
+
+struct tOut
+{
+    int outvalue;
+};
+extern struct tOut *out;
+
+extern int otherfunc(struct tEntry *);
+extern void anotherfunc(int val);
+
+void bar()
+{
+    struct tEntry entry = { 0 };
+
+    if (otherfunc(&entry) != 0)
+    {
+        return;
+    }
+
+    if (out)
+    {
+        out->outvalue = entry.value;
+    }
+
+    anotherfunc(5);
+}
+
+void foo()
+{
+    bar();
+}
-- 
2.52.0

Reply via email to