PR c++/67942 - diagnose placement new buffer overflow
authorMartin Sebor <msebor@redhat.com>
Fri, 6 Nov 2015 01:08:53 +0000 (01:08 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Fri, 6 Nov 2015 01:08:53 +0000 (18:08 -0700)
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

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

index b84778f32428edcd5d493e9c3e9f951c86d02d9d..1741fa2cfc0a22b1e806d5ba210139adb297c957 100644 (file)
@@ -1,3 +1,10 @@
+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
index 7600363447d1f50acc60021425d61e89571272b1..7386499d570936479970d80dc2aa0780db5f7ce0 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 c0a0d78ccc6c4a2d7f7de2fa30c96c9e1b3e56dc..eb518088d9142f98815d508ed94cadd3d0ee513f 100644 (file)
@@ -1,3 +1,10 @@
+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
index a8a2a686e559b112a124ef1355a55a121cbfeb1a..c0d753fae0e96bc6ba74b7da1ece74bd384c3203 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" }
+}