public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-2908] Diagnose mismatches between array and scalar new and delete [PR101791].
@ 2021-08-14 19:27 Martin Sebor
  0 siblings, 0 replies; only message in thread
From: Martin Sebor @ 2021-08-14 19:27 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:96194a07bdbc57dd9733892a791d87dbe25f0802

commit r12-2908-g96194a07bdbc57dd9733892a791d87dbe25f0802
Author: Martin Sebor <msebor@redhat.com>
Date:   Sat Aug 14 13:25:41 2021 -0600

    Diagnose mismatches between array and scalar new and delete [PR101791].
    
    Resolves:
    PR middle-end/101791 - missing warning on a mismatch between scalar and array forms of new and delete
    
    gcc/ChangeLog:
    
            PR middle-end/101791
            * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Use new argument
            to valid_new_delete_pair_p.
            * tree.c (valid_new_delete_pair_p): Add argument.
            * tree.h (valid_new_delete_pair_p): Same.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/101791
            * g++.dg/warn/Wmismatched-new-delete-6.C: New test.
            * g++.dg/warn/Wmismatched-new-delete-7.C: New test.

Diff:
---
 gcc/gimple-ssa-warn-access.cc                      |   9 +-
 .../g++.dg/warn/Wmismatched-new-delete-6.C         | 158 +++++++++++++++++++++
 .../g++.dg/warn/Wmismatched-new-delete-7.C         |  91 ++++++++++++
 gcc/tree.c                                         |  28 +++-
 gcc/tree.h                                         |   4 +-
 5 files changed, 284 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index a4559ddb5b3..93f43b711e2 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -1782,9 +1782,14 @@ new_delete_mismatch_p (tree new_decl, tree delete_decl)
 
   /* valid_new_delete_pair_p() returns a conservative result (currently
      it only handles global operators).  A true result is reliable but
-     a false result doesn't necessarily mean the operators don't match.  */
-  if (valid_new_delete_pair_p (new_name, delete_name))
+     a false result doesn't necessarily mean the operators don't match
+     unless CERTAIN is set.  */
+  bool certain;
+  if (valid_new_delete_pair_p (new_name, delete_name, &certain))
     return false;
+  /* CERTAIN is set when the negative result is certain.  */
+  if (certain)
+    return true;
 
   /* For anything not handled by valid_new_delete_pair_p() such as member
      operators compare the individual demangled components of the mangled
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C
new file mode 100644
index 00000000000..e19d00058b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C
@@ -0,0 +1,158 @@
+/* PR middle-end/101791 - missing warning on a mismatch between scalar
+   and array forms of new and delete
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std
+{
+#if __cplusplus >= 201703L
+enum class align_val_t: size_t { };
+#else
+enum align_val_t { };
+#endif
+
+struct nothrow_t { };
+const nothrow_t nothrow = { };
+
+}
+
+void* operator new (size_t);
+void* operator new (size_t, std::align_val_t);
+void* operator new (size_t, std::nothrow_t) throw ();
+void* operator new (size_t, std::align_val_t, std::nothrow_t) throw ();
+
+void* operator new[] (size_t);
+void* operator new[] (size_t, std::align_val_t);
+void* operator new[] (size_t, std::nothrow_t) throw ();
+void* operator new[] (size_t, std::align_val_t, std::nothrow_t) throw ();
+
+void operator delete (void*);
+void operator delete (void*, size_t);
+void operator delete (void*, std::align_val_t);
+void operator delete (void*, size_t, std::align_val_t);
+void operator delete (void*, std::nothrow_t) throw ();
+void operator delete (void*, std::align_val_t, std::nothrow_t) throw ();
+
+void operator delete[] (void*);
+void operator delete[] (void*, size_t);
+void operator delete[] (void*, std::align_val_t);
+void operator delete[] (void*, size_t, std::align_val_t);
+void operator delete[] (void*, std::nothrow_t) throw ();
+void operator delete[] (void*, std::align_val_t, std::nothrow_t) throw ();
+
+
+void sink (void*, ...);
+
+
+void nowarn_scalar_scalar ()
+{
+  {
+    int *p = new int;
+    sink (p);
+    delete p;
+  }
+
+  {
+    int *p = new (std::align_val_t (8)) int;
+    sink (p);
+    delete p;
+  }
+
+  {
+    int *p = new (std::nothrow) int;
+    sink (p);
+    delete p;
+  }
+
+  {
+    int *p = new (std::align_val_t (8), std::nothrow) int;
+    sink (p);
+    delete p;
+  }
+}
+
+void nowarn_array_array ()
+{
+  {
+    int *p = new int[__LINE__];
+    sink (p);
+    delete[] p;
+  }
+
+  {
+    int *p = new (std::align_val_t (8)) int[__LINE__];
+    sink (p);
+    delete[] p;
+  }
+
+  {
+    int *p = new (std::nothrow) int[__LINE__];
+    sink (p);
+    delete[] p;
+  }
+
+  {
+    int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__];
+    sink (p);
+    delete[] p;
+  }
+}
+
+
+
+void nowarn_scalar_array ()
+{
+  {
+    int *p = new int;   // { dg-message "returned from" }
+    sink (p);
+    delete[] p;         // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+
+  {
+    int *p = new (std::align_val_t (8)) int;
+    sink (p);
+    delete[] p;         // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+
+  {
+    int *p = new (std::nothrow) int;
+    sink (p);
+    delete[] p;         // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+
+  {
+    int *p = new (std::align_val_t (8), std::nothrow) int;
+    sink (p);
+    delete[] p;         // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+}
+
+
+void nowarn_array_scalar ()
+{
+  {
+    int *p = new int[__LINE__];
+    sink (p);
+    delete p;           // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+
+  {
+    int *p = new (std::align_val_t (8)) int[__LINE__];
+    sink (p);
+    delete p;           // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+
+  {
+    int *p = new (std::nothrow) int[__LINE__];
+    sink (p);
+    delete p;           // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+
+  {
+    int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__];
+    sink (p);
+    delete p;           // { dg-warning "\\\[-Wmismatched-new-delete" }
+  }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C
new file mode 100644
index 00000000000..67a5354b91d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C
@@ -0,0 +1,91 @@
+/* PR middle-end/101791 - missing warning on a mismatch between scalar
+   and array forms of new and delete
+   Verify that likely safe calls to technically mismatched member operator
+   new and delete are not diagnosed.  This test might need to be adjusted
+   if it turns out the assumptions GCC makes are overly conservative.
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std
+{
+#if __cplusplus >= 201703L
+enum class align_val_t: size_t { };
+#else
+enum align_val_t { };
+#endif
+
+struct nothrow_t { };
+const nothrow_t nothrow = { };
+
+}
+
+void sink (void*, ...);
+
+struct X { } x;
+struct Y { } y;
+
+struct A
+{
+  void* operator new (size_t);
+  void* operator new (size_t, std::align_val_t);
+
+  void* operator new (size_t, X);
+  void* operator new (size_t, Y);
+
+  void* operator new (size_t, std::align_val_t, X);
+  void* operator new (size_t, std::nothrow_t, Y);
+
+  /* A single operator delete callable on the result of calls to any
+     of the operator new overloads above (this may be too optimistic).  */
+  void operator delete (void*);
+};
+
+A* nowarn_align ()
+{
+  /* The following are likely okay given A's definition above but would
+     not be if A also defined an align_val_t overload of operator delete.  */
+  A *p = new (std::align_val_t (8)) A;
+  delete p;
+
+  return new (std::align_val_t (16)) A;
+}
+
+A* nowarn_X ()
+{
+  /* The following are also likely okay given A's definition above but
+     also would not be if A also defined an overload of operator delete
+     for X.  */
+  A *p = new (x) A;
+  delete p;
+  return new (x) A;
+}
+
+A* nowarn_Y ()
+{
+  // Same as above.
+  A *p = new (y) A;
+  delete p;
+  return new (y) A;
+}
+
+
+A* nowarn_align_X ()
+{
+  // Same as above.
+  A *p = new (std::align_val_t (32), x) A;
+  delete p;
+
+  return new (std::align_val_t (64), x) A;
+}
+
+
+A* nowarn_nothrow_Y ()
+{
+  // Same as above.
+  A *p = new (std::nothrow, y) A;
+  delete p;
+  return new (std::nothrow, y) A;
+}
+
diff --git a/gcc/tree.c b/gcc/tree.c
index a0ff79468eb..6ec8a9738c8 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -14314,17 +14314,28 @@ verify_type_context (location_t loc, type_context_kind context,
 	  || targetm.verify_type_context (loc, context, type, silent_p));
 }
 
-/* Return that NEW_ASM and DELETE_ASM name a valid pair of new and
-   delete operators.  */
+/* Return true if NEW_ASM and DELETE_ASM name a valid pair of new and
+   delete operators.  Return false if they may or may not name such
+   a pair and, when nonnull, set *PCERTAIN to true if they certainly
+   do not.  */
 
 bool
-valid_new_delete_pair_p (tree new_asm, tree delete_asm)
+valid_new_delete_pair_p (tree new_asm, tree delete_asm,
+			 bool *pcertain /* = NULL */)
 {
+  bool certain;
+  if (!pcertain)
+    pcertain = &certain;
+
   const char *new_name = IDENTIFIER_POINTER (new_asm);
   const char *delete_name = IDENTIFIER_POINTER (delete_asm);
   unsigned int new_len = IDENTIFIER_LENGTH (new_asm);
   unsigned int delete_len = IDENTIFIER_LENGTH (delete_asm);
 
+  /* The following failures are due to invalid names so they're not
+     considered certain mismatches.  */
+  *pcertain = false;
+
   if (new_len < 5 || delete_len < 6)
     return false;
   if (new_name[0] == '_')
@@ -14337,11 +14348,19 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm)
     ++delete_name, --delete_len;
   if (new_len < 4 || delete_len < 5)
     return false;
+
+  /* The following failures are due to names of user-defined operators
+     so they're also not considered certain mismatches.  */
+
   /* *_len is now just the length after initial underscores.  */
   if (new_name[0] != 'Z' || new_name[1] != 'n')
     return false;
   if (delete_name[0] != 'Z' || delete_name[1] != 'd')
     return false;
+
+  /* The following failures are certain mismatches.  */
+  *pcertain = true;
+
   /* _Znw must match _Zdl, _Zna must match _Zda.  */
   if ((new_name[2] != 'w' || delete_name[2] != 'l')
       && (new_name[2] != 'a' || delete_name[2] != 'a'))
@@ -14380,6 +14399,9 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm)
 	  && !memcmp (delete_name + 5, "St11align_val_tRKSt9nothrow_t", 29))
 	return true;
     }
+
+  /* The negative result is conservative.  */
+  *pcertain = false;
   return false;
 }
 
diff --git a/gcc/tree.h b/gcc/tree.h
index c3f302a406a..a26500dca61 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5406,7 +5406,9 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
 extern bool type_with_interoperable_signedness (const_tree);
 extern bitmap get_nonnull_args (const_tree);
 extern int get_range_pos_neg (tree);
-extern bool valid_new_delete_pair_p (tree, tree);
+
+/* Return true for a valid pair of new and delete operators.  */
+extern bool valid_new_delete_pair_p (tree, tree, bool * = NULL);
 
 /* Return simplified tree code of type that is used for canonical type
    merging.  */


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-14 19:27 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-14 19:27 [gcc r12-2908] Diagnose mismatches between array and scalar new and delete [PR101791] Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).