From 906f9ad995368b4891186c07ed3c5c2fd5f53bea Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 6 Nov 2015 01:08:53 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 7 +++ gcc/cp/init.c | 12 +++-- gcc/testsuite/ChangeLog | 7 +++ .../g++.dg/warn/Wplacement-new-size.C | 45 +++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b84778f3242..1741fa2cfc0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2015-11-05 Martin Sebor + + 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 PR c++/67942 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 7600363447d..7386499d570 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 c0a0d78ccc6..eb518088d91 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2015-11-05 Martin Sebor + + 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 PR c++/67942 diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C index a8a2a686e55..c0d753fae0e 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 struct TemplateClass { char c; }; + +// Declare a specialization but don't provide a definition. +template <> struct TemplateClass; + +// Declare an object of an explicit specialization of an unknown size. +extern TemplateClass 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 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" } +} -- 2.30.2