public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-1441] Teach compute_objsize about placement new [PR100876].
@ 2021-06-14 22:51 Martin Sebor
0 siblings, 0 replies; only message in thread
From: Martin Sebor @ 2021-06-14 22:51 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:d9f1466f88abef7c814d02ba39a6ea5ef420aaec
commit r12-1441-gd9f1466f88abef7c814d02ba39a6ea5ef420aaec
Author: Martin Sebor <msebor@redhat.com>
Date: Mon Jun 14 16:34:48 2021 -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.
Diff:
---
gcc/builtins.c | 47 ++++++++++++++++++++--
gcc/testsuite/g++.dg/analyzer/placement-new.C | 2 +
gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-6.C | 45 +++++++++++++++++++++
.../g++.dg/warn/Wmismatched-new-delete-4.C | 37 +++++++++++++++++
.../g++.dg/warn/Wmismatched-new-delete-5.C | 37 +++++++++++++++++
gcc/testsuite/g++.dg/warn/Wstringop-overflow-7.C | 42 +++++++++++++++++++
6 files changed, 207 insertions(+), 3 deletions(-)
diff --git a/gcc/builtins.c b/gcc/builtins.c
index af1fe49bb48..75419cc4edc 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5159,11 +5159,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:
@@ -13285,7 +13316,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? */
diff --git a/gcc/testsuite/g++.dg/analyzer/placement-new.C b/gcc/testsuite/g++.dg/analyzer/placement-new.C
index 8250f45b9d9..b648a428247 100644
--- a/gcc/testsuite/g++.dg/analyzer/placement-new.C
+++ b/gcc/testsuite/g++.dg/analyzer/placement-new.C
@@ -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
index 00000000000..83b6ff9157c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-6.C
@@ -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
index 00000000000..4320181e4d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-4.C
@@ -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
index 00000000000..92c75df40d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C
@@ -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
index 00000000000..d3d28f43d0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-7.C
@@ -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;
+}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2021-06-14 22:51 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-14 22:51 [gcc r12-1441] Teach compute_objsize about placement new [PR100876] 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).