// { dg-do run } // Origin: Mark Mitchell <mark@codesourcery.com> #if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 #include <cstdlib> #include <new> void* p; void* operator new[](size_t s) throw (std::bad_alloc) { // Record the base of the last array allocated. p = malloc (s); return p; } template <typename T> void check_no_cookie (int i) { void* a = new T[7]; if (p != a) exit (i); } template <typename T> void check_no_placement_cookie (int i) { p = malloc (13 * sizeof (T)); void* a = new (p) T[13]; if (p != a) exit (i); } template <typename T> void check_cookie (int i) { void* a = new T[11]; size_t x; // Compute the cookie location manually. #if defined(__ARM_EABI__) || defined(__le32__) x = 8; #else x = __alignof__ (T); if (x < sizeof (size_t)) x = sizeof (size_t); #endif if ((char *) a - x != (char *) p) exit (i); // Check the cookie value. size_t *sp = ((size_t *) a) - 1; if (*sp != 11) exit (i); #if defined(__ARM_EABI__) || defined(__le32__) sp = ((size_t *) a) - 2; if (*sp != sizeof (T)) exit (i); #endif } template <typename T> void check_placement_cookie (int i) { p = malloc (sizeof (T) * 11 + 100); void* a = new (p) T[11]; size_t x; // Compute the cookie location manually. #if defined(__ARM_EABI__) || defined(__le32__) x = 8; #else x = __alignof__ (T); if (x < sizeof (size_t)) x = sizeof (size_t); #endif if ((char *) a - x != (char *) p) exit (i); // Check the cookie value. size_t *sp = ((size_t *) a) - 1; if (*sp != 11) exit (i); #if defined(__ARM_EABI__) || defined(__le32__) sp = ((size_t *) a) - 2; if (*sp != sizeof (T)) exit (i); #endif } struct X {}; template <typename T> struct Y { int i; virtual void f () {} }; // A class with a non-trivial destructor -- it needs a cookie. struct Z { ~Z () {} }; // Likewise, but this class needs a bigger cookie so that the array // elements are correctly aligned. struct Z2 { ~Z2 () {} long double d; }; struct W1 { void operator delete[] (void *, size_t) {} }; struct W2 { void operator delete[] (void *) {} void operator delete[] (void *, size_t) {} }; struct W3 { void operator delete[] (void *, size_t) {} void operator delete[] (void *) {} }; struct W4 : public W1 {}; struct V { void *operator new[] (size_t s, void *p) { return p; } ~V () {} }; int main () { // There should be no cookies for types with trivial destructors. check_no_cookie<int> (1); check_no_cookie<X> (2); check_no_cookie<Y<double> > (3); // There should be no cookies for allocations using global placement // new. check_no_placement_cookie<int> (4); check_no_placement_cookie<X> (5); check_no_placement_cookie<Z> (6); // There should be a cookie when using a non-trivial destructor. check_cookie<Z> (7); check_cookie<Z2> (8); // There should be a cookie when using the two-argument array delete // operator. check_cookie<W1> (9); check_cookie<W4> (10); // But not when the one-argument version is also available. check_no_cookie<W2> (11); check_no_cookie<W3> (12); // There should be a cookie when using a non-global placement new. check_placement_cookie<V> (13); } #else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */ int main () { } #endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */