blob: ead7d3d433ef5f65064003247ac79a0f8cc851a7 [file] [edit]
/* **********************************************************
* Copyright (c) 2012-2019 Google, Inc. All rights reserved.
* **********************************************************/
/* Dr. Memory: the memory debugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License, and no later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Test nothrow and placement operators. Mismatches are already tested
* in cs2bug.cpp.
*/
#include <new> // For std::nothrow
#include <iostream>
#include "stdlib.h"
#include "limits.h"
// Windows compiler and gcc4.4.3 complain if the size is over 0x7fffffff;
// Clang and gcc 7.3.2 complain if it's over 0xfffffff.
#ifdef UNIX
# define SIZE_OOM 0xfffffff
#else
# define SIZE_OOM 0x7fffffff
#endif
#define SIZE_OOM_ARR 1024
#ifdef UNIX
# define IF_UNIX_ELSE(x,y) x
#else
# define IF_UNIX_ELSE(x,y) y
#endif
#ifdef X64
# define IF_X64_ELSE(x,y) x
#else
# define IF_X64_ELSE(x,y) y
#endif
class hasdtr {
public:
hasdtr() { x = new int[7]; }
~hasdtr() { delete[] x; }
int *x;
int y;
char z;
};
class enormous {
public:
/*
* i#972: char[SIZE_OOM] is the static limit but won't run OOM in Linux,
* so we alloc in a loop until OOM is triggered.
*/
char buf[SIZE_OOM];
};
static void
test_placement()
{
int *p = (int *) calloc(1, sizeof(hasdtr));
hasdtr *placed = new (p) hasdtr;
placed->y = 4;
if (((hasdtr *)p)->y != placed->y)
std::cout << "placement new not honored" << std::endl;
// Cannot call placement delete (only for language-internal use, e.g.,
// if constructor fails) so we must invoke destructor directly.
placed->~hasdtr();
free(p);
p = (int *) malloc(sizeof(hasdtr)*2);
placed = new (p) hasdtr[2];
// Cannot call placement delete (only for language-internal use, e.g.,
// if constructor fails) so we must invoke destructor directly.
placed[0].~hasdtr();
placed[1].~hasdtr();
free(p);
}
static void
test_nothrow()
{
#ifdef X64
// FIXME i#2029: taking too much time and resources to hit OOM w/ our allocator
std::cout << "new returned NULL" << std::endl;
std::cout << "new[] returned NULL" << std::endl;
return;
#endif
unsigned int i = 0;
enormous **e = new (std::nothrow) enormous*[SIZE_OOM_ARR];
for (i = 0; i < SIZE_OOM_ARR; i++) {
e[i] = new (std::nothrow) enormous;
std::cout << "i: " << i << std::endl;
if (e[i] == NULL) {
std::cout << "new returned NULL" << std::endl;
break;
}
}
for (unsigned int j = 0; j <= i && j < SIZE_OOM_ARR; j++)
delete e[j];
delete[] e;
IF_UNIX_ELSE(int *, char *) *p =
new (std::nothrow) IF_UNIX_ELSE(int *, char *)[SIZE_OOM_ARR];
for (i = 0; i < SIZE_OOM_ARR; i++) {
p[i] = new (std::nothrow) IF_UNIX_ELSE(int, char)[SIZE_OOM];
if (p[i] == NULL) {
std::cout << "new[] returned NULL" << std::endl;
break;
}
}
for (unsigned int j = 0; j <= i && j < SIZE_OOM_ARR; j++)
delete[] p[j];
delete[] p;
}
// Actually Dr. Memory is unable to throw an exception (i#957): it just aborts,
// so we must run this last, and we end up only testing new[] and not new.
static void
test_throw()
{
std::cout << "about to die" << std::endl;
try {
// On Linux if the size is too small we don't run out of memory until
// we've constructed most of the elements, which takes a long
// time and causes issues under drmem w/ DR doing resets, etc.
// gcc 7.3+ forces us to use the new smaller SIZE_OOM/2 for 32-bit,
// but that causes 64-bit to take forever here so we up it.
#ifdef X64
// We indirect through a variable for a larger size to avoid taking forever.
size_t count = 0x7ffffffffffff;
hasdtr *lots = new hasdtr[count];
#else
hasdtr *lots = new hasdtr[IF_UNIX_ELSE(SIZE_OOM/2,SIZE_OOM/sizeof(hasdtr))];
#endif
lots[0].y = 4;
} catch (std::bad_alloc&) {
std::cout << "caught bad_alloc" << std::endl;
}
}
int
main()
{
test_placement();
test_nothrow();
// This one won't return under Dr. Memory!
test_throw();
std::cout << "all done" << std::endl;
return 0;
}