aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2015-11-06 01:08:53 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2015-11-05 18:08:53 -0700
commit906f9ad995368b4891186c07ed3c5c2fd5f53bea (patch)
tree290722de96f765a33eafce59384bc6741c175d1a /gcc
parent925b6a76e2d352c7a59119a4179db953ad30af00 (diff)
downloadgcc-906f9ad995368b4891186c07ed3c5c2fd5f53bea.zip
gcc-906f9ad995368b4891186c07ed3c5c2fd5f53bea.tar.gz
gcc-906f9ad995368b4891186c07ed3c5c2fd5f53bea.tar.bz2
PR c++/67942 - diagnose placement new buffer overflow
gcc/cp/ * cp/init.c (warn_placement_new_too_small): Avoid assuming the size of the first operand of placement new or its type is known. gcc/testsuite/ * g++.dg/warn/Wplacement-new-size.C: Exercise placement new invocations where the size of the destination buffer object or its type (or both) is unknown. From-SVN: r229831
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/init.c12
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/warn/Wplacement-new-size.C45
4 files changed, 68 insertions, 3 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b84778f..1741fa2 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,6 +1,13 @@
2015-11-05 Martin Sebor <msebor@redhat.com>
PR c++/67942
+ * cp/init.c (warn_placement_new_too_small): Avoid assuming
+ the size of the first operand of placement new or its type
+ is known.
+
+2015-11-05 Martin Sebor <msebor@redhat.com>
+
+ PR c++/67942
* cp/init.c (warn_placement_new_too_small): New function.
(build_new_1): Call it.
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 7600363..7386499 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2384,20 +2384,26 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
/* Treat members of unions and members of structs uniformly, even
though the size of a member of a union may be viewed as extending
to the end of the union itself (it is by __builtin_object_size). */
- if (TREE_CODE (oper) == VAR_DECL || use_obj_size)
+ if ((TREE_CODE (oper) == VAR_DECL || use_obj_size)
+ && DECL_SIZE_UNIT (oper))
{
/* Use the size of the entire array object when the expression
refers to a variable or its size depends on an expression
that's not a compile-time constant. */
- bytes_avail = tree_to_shwi (DECL_SIZE_UNIT (oper));
+ bytes_avail = tree_to_uhwi (DECL_SIZE_UNIT (oper));
exact_size = !use_obj_size;
}
- else
+ else if (TYPE_SIZE_UNIT (TREE_TYPE (oper)))
{
/* Use the size of the type of the destination buffer object
as the optimistic estimate of the available space in it. */
bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (oper)));
}
+ else
+ {
+ /* Bail if neither the size of the object nor its type is known. */
+ return;
+ }
/* Avoid diagnosing flexible array members (accepted as an extension
and diagnosed with -Wpedantic).
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c0a0d78..eb51808 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,6 +1,13 @@
2015-11-05 Martin Sebor <msebor@redhat.com>
PR c++/67942
+ * g++.dg/warn/Wplacement-new-size.C: Exercise placement new
+ invocations where the size of the destination buffer object
+ or its type (or both) is unknown.
+
+2015-11-05 Martin Sebor <msebor@redhat.com>
+
+ PR c++/67942
* g++.dg/warn/Wplacement-new-size.C: New test.
2015-11-05 Alan Lawrence <alan.lawrence@arm.com>
diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
index a8a2a68..c0d753f 100644
--- a/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
+++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
@@ -408,3 +408,48 @@ void test_user_defined_placement_new ()
new (&x) ClassWithGlobalNew[2];
}
}
+
+extern char extbuf[];
+
+template <class> struct TemplateClass { char c; };
+
+// Declare a specialization but don't provide a definition.
+template <> struct TemplateClass<void>;
+
+// Declare an object of an explicit specialization of an unknown size.
+extern TemplateClass<void> exttempl_void;
+
+// Verify that no warning is issued when placement new is called with
+// an extern buffer of unknown size (and the case is handled gracefully
+// and doesn't cause an ICE).
+static __attribute__ ((used))
+void test_extern_buffer_of_unknown_size ()
+{
+ new (extbuf) int ();
+ new (extbuf) int [1024];
+
+ new (&exttempl_void) int ();
+ new (&exttempl_void) int [1024];
+}
+
+extern char extbuf_size_int [sizeof (int)];
+
+extern TemplateClass<int> exttempl;
+
+// Verify that a warning is issued as expected when placement new is
+// called with an extern buffer of known size (and the case is handled
+// gracefully and doesn't cause an ICE).
+static __attribute__ ((used))
+void test_extern_buffer ()
+{
+ new (extbuf_size_int) int ();
+ new (extbuf_size_int) int [1];
+
+ struct S { int a [2]; };
+
+ new (extbuf_size_int) S; // { dg-warning "placement" }
+ new (extbuf_size_int) int [2]; // { dg-warning "placement" }
+
+ new (&exttempl) int (); // { dg-warning "placement" }
+ new (&exttempl) int [1024]; // { dg-warning "placement" }
+}