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 there is a possible path from
the invalidating statement block to the use block without any
intervening blocks that may clobber or assign to the storage in
question.
This resolves all outstanding false positives with -Wdangling-pointers
in bugzilla.
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]>
---
Testing notes:
- Tested on x86_64 to verify that there are no new regressions. Also
verified with the preprocessesed sqlite reproducer in pr124141.
- i686 test run in progress.
- x86_64 bootstrap in progress.
gcc/gimple-ssa-warn-access.cc | 64 ++++++++++++++++++-
.../c-c++-common/Wdangling-pointer-pr110091.c | 40 ++++++++++++
2 files changed, 101 insertions(+), 3 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..a7155037d8a 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3854,6 +3854,53 @@ pass_waccess::maybe_check_dealloc_call (gcall *call)
}
}
+/* Return true if there is a path from FROM to TO where CLOBVAR has not been
+ written to. INVAL_BB is the original FROM that was passed in from the
+ toplevel caller, VISITED logs the basic blocks that have been previously
+ visited. */
+
+static bool
+can_reach_from (basic_block inval_bb, basic_block from, basic_block to,
+ tree clobvar, hash_set<basic_block> &visited)
+{
+ edge_iterator ei;
+ edge e;
+
+ /* Skip over inval_bb. */
+ if (inval_bb != from)
+ for (auto gsi = gsi_start_bb (from); !gsi_end_p (gsi);
+ gsi_next_nondebug (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ if (gimple_code (stmt) == GIMPLE_ASSIGN
+ && clobvar == gimple_assign_lhs (stmt))
+ return false;
+ }
+
+ FOR_EACH_EDGE (e, ei, from->succs)
+ {
+ if (e->flags & (EDGE_EH | EDGE_ABNORMAL | EDGE_DFS_BACK))
+ continue;
+
+ /* Punt on loops. */
+ if (visited.add (e->dest))
+ continue;
+
+ if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+ continue;
+
+ /* If we reach TO, also check if CLOBVAR is being clobbered or assigned
+ to anywhere between it and the exit block. */
+ if (e->dest == to)
+ return true;
+
+ if (can_reach_from (inval_bb, e->dest, to, clobvar, 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
@@ -3874,6 +3921,7 @@ pass_waccess::use_after_inval_p (gimple *inval_stmt,
gimple *use_stmt,
if (inval_bb != use_bb)
{
+ /* Look for a quick win with dominator information. */
if (dominated_by_p (CDI_DOMINATORS, use_bb, inval_bb))
return true;
@@ -3907,10 +3955,20 @@ 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
+ /* 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);
+ point. If there's a path from INVAL_BB to USE_BB without any
+ assignments or clobbers to CLOBVAR, 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, inval_bb, use_bb, clobvar, 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