From patchwork Fri Nov 2 12:09:32 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [PING^2,C++] Add overflow checking to __cxa_vec_new[23] Date: Fri, 02 Nov 2012 02:09:32 -0000 From: Florian Weimer X-Patchwork-Id: 196549 Message-Id: <5093B7FC.30201@redhat.com> To: Paolo Carlini Cc: gcc-patches@gcc.gnu.org, libstdc++ , Jason Merrill On 10/30/2012 05:30 PM, Florian Weimer wrote: > On 10/30/2012 05:17 PM, Paolo Carlini wrote: > >> Sorry, I don't know the code well enough to review your patch, but >> since I'm in CC, I still don't understand why, instead of adding a >> full libstdc++ testcase you are extending a C++ testcase, in old-deja >> even, normally considered legacy. > > AFAIK, this is the only place we have such a test. I suppose I could it > put it into testsuite/18_support, but I would have to duplicate a bit of > the machinery of the original test case because I can't just write a > class and take the address of its constructor and destructor (whose > addresses are passed to the tested functions). I really didn't want to > do that because there are some platform dependencies (the __ARM_EABI__ > #ifdef). I looked at this again and made a new copy of the test case instead. It has been successfully tested on x86_64-redhat-linux-gnu. Is this okay for trunk? 2012-11-02 Florian Weimer * libsupc++/vec.cc (compute_size): New. (__cxa_vec_new2, __cxa_vec_new3): Use it. * testsuite/18_support/cxa_vec.cc: New. diff --git a/libstdc++-v3/libsupc++/vec.cc b/libstdc++-v3/libsupc++/vec.cc index 700c5ef..bfce117 100644 --- a/libstdc++-v3/libsupc++/vec.cc +++ b/libstdc++-v3/libsupc++/vec.cc @@ -1,6 +1,6 @@ // New abi Support -*- C++ -*- -// Copyright (C) 2000, 2001, 2003, 2004, 2009, 2011 +// Copyright (C) 2000-2012 // Free Software Foundation, Inc. // // This file is part of GCC. @@ -59,6 +59,19 @@ namespace __cxxabiv1 globals->caughtExceptions = p->nextException; globals->uncaughtExceptions += 1; } + + // Compute the total size with overflow checking. + std::size_t compute_size(std::size_t element_count, + std::size_t element_size, + std::size_t padding_size) + { + if (element_size && element_count > std::size_t(-1) / element_size) + throw std::bad_alloc(); + std::size_t size = element_count * element_size; + if (size + padding_size < size) + throw std::bad_alloc(); + return size + padding_size; + } } // Allocate and construct array. @@ -83,7 +96,8 @@ namespace __cxxabiv1 void *(*alloc) (std::size_t), void (*dealloc) (void *)) { - std::size_t size = element_count * element_size + padding_size; + std::size_t size + = compute_size(element_count, element_size, padding_size); char *base = static_cast (alloc (size)); if (!base) return base; @@ -124,7 +138,8 @@ namespace __cxxabiv1 void *(*alloc) (std::size_t), void (*dealloc) (void *, std::size_t)) { - std::size_t size = element_count * element_size + padding_size; + std::size_t size + = compute_size(element_count, element_size, padding_size); char *base = static_cast(alloc (size)); if (!base) return base; diff --git a/libstdc++-v3/testsuite/18_support/cxa_vec.cc b/libstdc++-v3/testsuite/18_support/cxa_vec.cc new file mode 100644 index 0000000..5558f22 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/cxa_vec.cc @@ -0,0 +1,64 @@ +// { dg-do run } +// Avoid use of none-overridable new/delete operators in shared +// { dg-options "-static" { target *-*-mingw* } } +// Test __cxa_vec routines +// Copyright (C) 2000-2012 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 7 Apr 2000 + +#include +#include +#include +#include +#include + +// Allocate enough padding to hold an array cookie. +#ifdef __ARM_EABI__ +static const size_t padding = 8; +#else +static const size_t padding = (sizeof (std::size_t)); +#endif + +// our pseudo ctors and dtors +static abi::__cxa_cdtor_return_type ctor (void *x) +{ + abort (); +} + +static abi::__cxa_cdtor_return_type dtor (void *x) +{ + abort (); +} + +static const std::size_t large_size = std::size_t(1) << (sizeof(std::size_t) * 8 - 2); + +// allocate an array whose size causes an overflow during addition +void test1 () +{ + try + { + abi::__cxa_vec_new (large_size, 4, padding, ctor, dtor); + abort (); + } + catch (std::bad_alloc &) + { + } +} + +// allocate an array whose size causes an overflow during multiplication +void test2 () +{ + try + { + abi::__cxa_vec_new (std::size_t(-1) / 4, 4, padding, ctor, dtor); + abort (); + } + catch (std::bad_alloc &) + { + } +} + +int main () +{ + test1 (); + test2 (); +}