https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104492

--- Comment #9 from Richard Biener <rguenth at gcc dot gnu.org> ---
So IL wise the issue is that we go from

  <bb 2> :
  candidates(address-taken)[0].m_size = 2;
  candidates(address-taken)[0].m_data = "so";
  _1 = std::end<const QLatin1String, 1> (&candidates(address-taken));
  _2 = std::begin<const QLatin1String, 1> (&candidates(address-taken));
  _11 = std::find<const QLatin1String*, QStringView> (_2, _1,
&s(address-taken));
  _3 = _11;
  _4 = std::end<const QLatin1String, 1> (&candidates(address-taken));
  _13 = _3 != _4;
  candidates(address-taken) ={v} {CLOBBER(eol)};
  return _13;

to

  _32 = std::__find_if<const QLatin1String*,
__gnu_cxx::__ops::_Iter_equals_val<const QStringView> >
(&candidates(address-taken), &MEM <const struct QLatin1String[1]> [(void
*)&candidates(address-taken) + 16B], __pred, D.182436);
  __pred ={v} {CLOBBER(eol)};
  _33 = &MEM <const struct QLatin1String[1]> [(void
*)&candidates(address-taken) + 16B] != _32;
  candidates(address-taken) ={v} {CLOBBER(eol)};
  _66 = _33;
  s(address-taken) ={v} {CLOBBER(eol)};
  _19 = _66;
  retval.0_20 = _19;
  D.169966(address-taken) ={v} {CLOBBER(eol)};
  if (retval.0_20 != 0)

exposing the forwarding opportunity into the conditional:

  _32 = std::__find_if<const QLatin1String*,
__gnu_cxx::__ops::_Iter_equals_val<const QStringView> >
(&candidates(address-taken), &MEM <const struct QLatin1String[1]> [(void
*)&candidates(address-taken) + 16B], __pred, D.182436);
  __pred ={v} {CLOBBER(eol)};
  candidates(address-taken) ={v} {CLOBBER(eol)};
  s(address-taken) ={v} {CLOBBER(eol)};
  D.169966 ={v} {CLOBBER(eol)};
  if (&MEM <const struct QLatin1String[1]> [(void *)&candidates(address-taken)
+ 16B] != _32)

as noted CLOBBERs are not barriers for values but only for memory so any
such forwarding (which would also happen for non-equality compares) interferes
with the intent of -Wdangling-pointer.  I'll note that a CLOBBER does _not_
invalidate the pointer to the storage but only its contents as opposed to
some reading of 'realloc' or 'free' semantics imposed by the C standard.

The documentation mentions two levels of -Wdangling-pointer but all examples
are about either the pointer escaping the function (to the caller) or about
accesses to the storage whose contents became indeterminate.

Unrolling and IVOPTs/SLSR could also expose re-use of storage accessed by
a pointer to the "first" instance of a variable.

I'm not sure what can be done about all this for the late pass_warn_access
(which runs _very_ late).  It's going to be prone to such issues and
maybe -Wanalyzer is a better tool for the purpose.

I was not successful in auto-reducing the testcase to something that
closely resembles the above IL but I guess crafting a manual testcase
from it would be possible.

For the specific case we now pass 'equality' to
pass_waccess::warn_invalid_pointer which is true for the original testcase
but is only used to prune diagnostics after free/realloc and not when
using the (undocumented) -Wdangling-pointer=3 level (level 3 is also rejected
because it has IntegerRange(0, 2)).

This case is about iteration over an auto variable and the "found" check
being forwarded across the storage invalidation.

The following fixes the original (and my misreduced) testcase.  I'm going
to test it and post it for review.

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 879dbcc1e52..6c404f18db7 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3896,13 +3896,13 @@ pass_waccess::warn_invalid_pointer (tree ref, gimple
*us
e_stmt,
        return;
     }

+  if ((equality && warn_use_after_free < 3)
+      || (maybe && warn_use_after_free < 2)
+      || warning_suppressed_p (use_stmt, OPT_Wuse_after_free))
+    return;
+
   if (is_gimple_call (inval_stmt))
     {
-      if ((equality && warn_use_after_free < 3)
-         || (maybe && warn_use_after_free < 2)
-         || warning_suppressed_p (use_stmt, OPT_Wuse_after_free))
-       return;
-
       const tree inval_decl = gimple_call_fndecl (inval_stmt);

       if ((ref && warning_at (use_loc, OPT_Wuse_after_free,
@@ -3923,10 +3923,6 @@ pass_waccess::warn_invalid_pointer (tree ref, gimple
*use_stmt,
       return;
     }

-  if ((maybe && warn_dangling_pointer < 2)
-      || warning_suppressed_p (use_stmt, OPT_Wdangling_pointer_))
-    return;
-
   if (DECL_NAME (var))
     {
       if ((ref

Reply via email to