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.cc: New test.
Signed-off-by: Siddhesh Poyarekar <[email protected]>
---
Testing:
- Bootstrapped and tested on x86_64, no new failures
- Bootstrap for config=ubsan in progress
- Build and tested i686, no new failures.
gcc/gimple-ssa-warn-access.cc | 38 +++++++++++++++++----------
gcc/passes.def | 6 ++---
gcc/testsuite/g++.dg/warn/pr123374.cc | 29 ++++++++++++++++++++
3 files changed, 56 insertions(+), 17 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/warn/pr123374.cc
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 44e62475cfa..df34da2bf96 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 54b56b3c0c8..4586d2cf6ad 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.cc
b/gcc/testsuite/g++.dg/warn/pr123374.cc
new file mode 100644
index 00000000000..cf777672aa7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/pr123374.cc
@@ -0,0 +1,29 @@
+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;
+ }
+}
--
2.52.0