PR c++/67942 - diagnose placement new buffer overflow
authormsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 Nov 2015 01:08:53 +0000 (01:08 +0000)
committermsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 Nov 2015 01:08:53 +0000 (01:08 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@229831 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/init.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wplacement-new-size.C

index b84778f..1741fa2 100644 (file)
@@ -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.
 
index 7600363..7386499 100644 (file)
@@ -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).
index c0a0d78..eb51808 100644 (file)
@@ -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>
index a8a2a68..c0d753f 100644 (file)
@@ -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" }
+}