]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
warn-access: Prevent -Wuse-after-free on ARM [PR104213]
authorMarek Polacek <polacek@redhat.com>
Tue, 25 Jan 2022 20:12:51 +0000 (15:12 -0500)
committerMarek Polacek <polacek@redhat.com>
Wed, 26 Jan 2022 17:18:32 +0000 (12:18 -0500)
Here, -Wuse-after-free warns about using 'this' which, on ARM, cdtors
return, as mandated by the EABI.  To be entirely correct, it only
requires it for C1 and C2 ctors and D2 and D1 dtors, but I don't feel
like changing that now and possibly running into issues later on.

This patch uses suppress_warning on 'this' for certain cdtor_returns_this
cases in the C++ FE, and then warn_invalid_pointer makes use of this
information and doesn't warn.

In my first attempt I tried suppress_warning the MODIFY_EXPR or RETURN_EXPR
we build in build_delete_destructor_body, but the complication is that
the suppress_warning bits don't always survive gimplification; see e.g.
gimplify_modify_expr where we do

 6130       if (COMPARISON_CLASS_P (*from_p))
 6131         copy_warning (assign, *from_p);

but here we're not dealing with a comparison.  Removing that check
regresses uninit-pr74762.C.  Adding copy_warning (assign, *expr_p)
regresses c-c++-common/uninit-17.c.

PR target/104213

gcc/cp/ChangeLog:

* decl.cc (finish_constructor_body): Suppress -Wuse-after-free.
(finish_destructor_body): Likewise.
* optimize.cc (build_delete_destructor_body): Likewise.

gcc/ChangeLog:

* gimple-ssa-warn-access.cc (pass_waccess::warn_invalid_pointer): Don't
warn when the SSA_NAME_VAR of REF has supressed -Wuse-after-free.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Wuse-after-free2.C: New test.
* g++.dg/warn/Wuse-after-free3.C: New test.

gcc/cp/decl.cc
gcc/cp/optimize.cc
gcc/gimple-ssa-warn-access.cc
gcc/testsuite/g++.dg/warn/Wuse-after-free2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wuse-after-free3.C [new file with mode: 0644]

index 22d3dd1e2ad59a8583ecb6d3ade4f98f82d57897..6534a7fd320eb6b531a092a0ef9714feb4cafade 100644 (file)
@@ -17315,6 +17315,7 @@ finish_constructor_body (void)
       add_stmt (build_stmt (input_location, LABEL_EXPR, cdtor_label));
 
       val = DECL_ARGUMENTS (current_function_decl);
+      suppress_warning (val, OPT_Wuse_after_free);
       val = build2 (MODIFY_EXPR, TREE_TYPE (val),
                    DECL_RESULT (current_function_decl), val);
       /* Return the address of the object.  */
@@ -17408,6 +17409,7 @@ finish_destructor_body (void)
       tree val;
 
       val = DECL_ARGUMENTS (current_function_decl);
+      suppress_warning (val, OPT_Wuse_after_free);
       val = build2 (MODIFY_EXPR, TREE_TYPE (val),
                    DECL_RESULT (current_function_decl), val);
       /* Return the address of the object.  */
index 4ad3f1dc9aa8f1497fc5d255511cb4e7a6bf7632..13ab8b7361ed8a64f796e0dcbbaad45600709671 100644 (file)
@@ -166,6 +166,7 @@ build_delete_destructor_body (tree delete_dtor, tree complete_dtor)
   if (targetm.cxx.cdtor_returns_this ())
     {
       tree val = DECL_ARGUMENTS (delete_dtor);
+      suppress_warning (val, OPT_Wuse_after_free);
       val = build2 (MODIFY_EXPR, TREE_TYPE (val),
                     DECL_RESULT (delete_dtor), val);
       add_stmt (build_stmt (0, RETURN_EXPR, val));
index afcf0f71becae5032e5cc0322779fca19ad84eda..3dcaf4230b85bfeee304cfbc734c09696eda1d7a 100644 (file)
@@ -3880,9 +3880,17 @@ pass_waccess::warn_invalid_pointer (tree ref, gimple *use_stmt,
                                    bool maybe, bool equality /* = false */)
 {
   /* Avoid printing the unhelpful "<unknown>" in the diagnostics.  */
-  if (ref && TREE_CODE (ref) == SSA_NAME
-      && (!SSA_NAME_VAR (ref) || DECL_ARTIFICIAL (SSA_NAME_VAR (ref))))
-    ref = NULL_TREE;
+  if (ref && TREE_CODE (ref) == SSA_NAME)
+    {
+      tree var = SSA_NAME_VAR (ref);
+      if (!var)
+       ref = NULL_TREE;
+      /* Don't warn for cases like when a cdtor returns 'this' on ARM.  */
+      else if (warning_suppressed_p (var, OPT_Wuse_after_free))
+       return;
+      else if (DECL_ARTIFICIAL (var))
+       ref = NULL_TREE;
+    }
 
   location_t use_loc = gimple_location (use_stmt);
   if (use_loc == UNKNOWN_LOCATION)
diff --git a/gcc/testsuite/g++.dg/warn/Wuse-after-free2.C b/gcc/testsuite/g++.dg/warn/Wuse-after-free2.C
new file mode 100644 (file)
index 0000000..6d5f2bf
--- /dev/null
@@ -0,0 +1,10 @@
+// PR target/104213
+// { dg-do compile }
+// { dg-options "-Wuse-after-free" }
+
+class C
+{
+    virtual ~C();
+};
+
+C::~C() {} // { dg-bogus "used after" }
diff --git a/gcc/testsuite/g++.dg/warn/Wuse-after-free3.C b/gcc/testsuite/g++.dg/warn/Wuse-after-free3.C
new file mode 100644 (file)
index 0000000..1862ac8
--- /dev/null
@@ -0,0 +1,16 @@
+// PR target/104213
+// { dg-do compile }
+// { dg-options "-Wuse-after-free" }
+// FIXME: We should not output the warning twice.
+
+struct A
+{
+  virtual ~A ();
+  void f ();
+};
+
+A::~A ()
+{
+  operator delete (this);
+  f (); // { dg-warning "used after" }
+} // { dg-warning "used after" }