]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Backported from trunk:
authorMartin Sebor <msebor@redhat.com>
Thu, 17 Jun 2021 18:18:53 +0000 (12:18 -0600)
committerMartin Sebor <msebor@redhat.com>
Thu, 17 Jun 2021 20:07:15 +0000 (14:07 -0600)
Teach compute_objsize about placement new [PR100876].

Resolves:
PR c++/100876 - -Wmismatched-new-delete should understand placement new when it's not inlined

gcc/ChangeLog:

PR c++/100876
* builtins.c (gimple_call_return_array): Check for attribute fn spec.
Handle calls to placement new.
(ndecl_dealloc_argno): Avoid placement delete.

gcc/testsuite/ChangeLog:

PR c++/100876
* g++.dg/warn/Wmismatched-new-delete-4.C: New test.
* g++.dg/warn/Wmismatched-new-delete-5.C: New test.
* g++.dg/warn/Wstringop-overflow-7.C: New test.
* g++.dg/warn/Wfree-nonheap-object-6.C: New test.
* g++.dg/analyzer/placement-new.C: Prune out expected warning.

gcc/builtins.c
gcc/testsuite/g++.dg/analyzer/placement-new.C
gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wstringop-overflow-7.C [new file with mode: 0644]

index 4c2ed1cb14331b25db8e5ae2a3e3741d1725576b..6f3ace5d1248529c6a2349bcd88d01d1512697c1 100644 (file)
@@ -5147,11 +5147,42 @@ static tree
 gimple_call_return_array (gimple *stmt, offset_int offrng[2],
                          range_query *rvals)
 {
-  if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
-      || gimple_call_num_args (stmt) < 1)
+  {
+    /* Check for attribute fn spec to see if the function returns one
+       of its arguments.  */
+    attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
+    unsigned int argno;
+    if (fnspec.returns_arg (&argno))
+      {
+       offrng[0] = offrng[1] = 0;
+       return gimple_call_arg (stmt, argno);
+      }
+  }
+
+  if (gimple_call_num_args (stmt) < 1)
     return NULL_TREE;
 
   tree fn = gimple_call_fndecl (stmt);
+  if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+    {
+      /* See if this is a call to placement new.  */
+      if (!fn
+         || !DECL_IS_OPERATOR_NEW_P (fn)
+         || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fn))
+       return NULL_TREE;
+
+      tree fname = DECL_ASSEMBLER_NAME (fn);
+      if (!id_equal (fname, "_ZnwmPv")       // ordinary form
+         && !id_equal (fname, "_ZnamPv"))   // array form
+       return NULL_TREE;
+
+      if (gimple_call_num_args (stmt) != 2)
+       return NULL_TREE;
+
+      offrng[0] = offrng[1] = 0;
+      return gimple_call_arg (stmt, 1);
+    }
+
   switch (DECL_FUNCTION_CODE (fn))
     {
     case BUILT_IN_MEMCPY:
@@ -13079,7 +13110,17 @@ fndecl_dealloc_argno (tree fndecl)
 {
   /* A call to operator delete isn't recognized as one to a built-in.  */
   if (DECL_IS_OPERATOR_DELETE_P (fndecl))
-    return 0;
+    {
+      if (DECL_IS_REPLACEABLE_OPERATOR (fndecl))
+       return 0;
+
+      /* Avoid placement delete that's not been inlined.  */
+      tree fname = DECL_ASSEMBLER_NAME (fndecl);
+      if (id_equal (fname, "_ZdlPvS_")       // ordinary form
+         || id_equal (fname, "_ZdaPvS_"))   // array form
+       return UINT_MAX;
+      return 0;
+    }
 
   /* TODO: Handle user-defined functions with attribute malloc?  Handle
      known non-built-ins like fopen?  */
index 8250f45b9d9657a033b8e595f87b13271d200735..b648a428247710231f0f9a003faf97f17f99ab65 100644 (file)
@@ -24,3 +24,5 @@ void test_3 (void)
   int *p = new(buf) int (42);
   delete p; // { dg-warning "memory not on the heap" }
 }
+
+// { dg-prune-output "-Wfree-nonheap-object" }
diff --git a/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-6.C b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-6.C
new file mode 100644 (file)
index 0000000..83b6ff9
--- /dev/null
@@ -0,0 +1,45 @@
+/* { dg-do compile }
+   { dg-options "-O0 -Wall" } */
+
+#if __cplusplus < 201103L
+# define noexcept throw ()
+#endif
+
+void* operator new (__SIZE_TYPE__, void* __p) noexcept;
+void operator delete (void*, void*);
+
+void* operator new[] (__SIZE_TYPE__, void* __p) noexcept;
+void operator delete[] (void*, void*) noexcept;
+
+struct A { A (); ~A (); int i; };
+
+extern void *p;
+
+void nowarn_placement_new ()
+{
+  char a[sizeof (A)];
+  p = new (a) A ();           // { dg-bogus "-Wfree-nonheap-object" }
+}
+
+
+void warn_placement_new ()
+{
+  char a[sizeof (A)];
+  p = new (a + 1) A ();       // { dg-warning "\\\[-Wplacement-new" }
+                              // { dg-bogus "-Wfree-nonheap-object" "bogus" { target *-*-* } .-1 }
+}
+
+
+void nowarn_placement_new_array ()
+{
+  char a[sizeof (A)];
+  p = new (a) A[1];           // { dg-bogus "-Wfree-nonheap-object" }
+}
+
+
+void warn_placement_new_array ()
+{
+  char a[sizeof (A)];
+  p = new (a + 1) A[1];       // { dg-warning "\\\[-Wplacement-new" }
+                              // { dg-bogus "-Wfree-nonheap-object" "bogus" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-4.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-4.C
new file mode 100644 (file)
index 0000000..4320181
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR c++/100876 - -Wmismatched-new-delete should either look through
+   or ignore placement new
+   { dg-do compile }
+   { dg-options "-O0 -Wall" } */
+
+extern "C" {
+  void* malloc (__SIZE_TYPE__);
+  void free (void*);
+}
+
+void* operator new (__SIZE_TYPE__, void*);
+void* operator new[] (__SIZE_TYPE__, void*);
+
+void nowarn_placement_new ()
+{
+  free (new (malloc (sizeof (int))) int ());      // { dg-bogus "-Wmismatched-new-delete" }
+}
+
+void nowarn_placement_array_new ()
+{
+  free (new (malloc (sizeof (int) * 2)) int[2]);  // { dg-bogus "-Wmismatched-new-delete" }
+}
+
+
+void warn_placement_new ()
+{
+  void *p = malloc (sizeof (int));
+  int *q = new (p) int ();
+  delete q;                   // { dg-warning "-Wmismatched-new-delete" }
+}
+
+void warn_placement_array_new ()
+{
+  void *p = malloc (sizeof (int));
+  int *q = new (p) int[2];
+  delete q;                   // { dg-warning "-Wmismatched-new-delete" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C
new file mode 100644 (file)
index 0000000..92c75df
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR c++/100876 - -Wmismatched-new-delete should either look through
+   or ignore placement new
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+extern "C" {
+  void* malloc (__SIZE_TYPE__);
+  void free (void*);
+}
+
+inline void* operator new (__SIZE_TYPE__, void *p) { return p; }
+inline void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
+void nowarn_placement_new ()
+{
+  free (new (malloc (sizeof (int))) int ());      // { dg-bogus "-Wmismatched-new-delete" }
+}
+
+void nowarn_placement_array_new ()
+{
+  free (new (malloc (sizeof (int) * 2)) int[2]);  // { dg-bogus "-Wmismatched-new-delete" }
+}
+
+
+void warn_placement_new ()
+{
+  void *p = malloc (sizeof (int));
+  int *q = new (p) int ();
+  delete q;                   // { dg-warning "-Wmismatched-new-delete" }
+}
+
+void warn_placement_array_new ()
+{
+  void *p = malloc (sizeof (int));
+  int *q = new (p) int[2];
+  delete q;                   // { dg-warning "-Wmismatched-new-delete" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-7.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-7.C
new file mode 100644 (file)
index 0000000..d3d28f4
--- /dev/null
@@ -0,0 +1,42 @@
+/* PR c++/100876 - -Wmismatched-new-delete should either look through
+   or ignore placement new
+   { dg-do compile }
+   { dg-options "-O0 -Wall -Wno-array-bounds" } */
+
+inline void* operator new (__SIZE_TYPE__, void *p) { return p; }
+inline void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
+void* nowarn_placement_new_memset ()
+{
+  struct S { int i; };
+  void *p = __builtin_malloc (sizeof (S));
+  S *q = new (p) S;
+  __builtin_memset (q, 0, sizeof (S));
+  return q;
+}
+
+void* warn_placement_new_memset ()
+{
+  struct S { int i; };
+  void *p = __builtin_malloc (sizeof (S));
+  S *q = new (p) S;
+  __builtin_memset (q, 0, sizeof (S) + 1);  // { dg-warning "\\\[-Wstringop-overflow" }
+  return q;
+}
+
+void* nowarn_placement_new_array_strncpy (const char *s)
+{
+  void *p = __builtin_malloc (5);
+  char *q = new (p) char[5];
+  __builtin_strncpy (q, s, 5);
+  return q;
+
+}
+
+void* warn_placement_new_array_strncpy (const char *s)
+{
+  void *p = __builtin_malloc (4);
+  char *q = new (p) char[5];
+  __builtin_strncpy (q, s, 5);  // { dg-warning "\\\[-Wstringop-overflow" }
+  return q;
+}