summaryrefslogtreecommitdiff
path: root/src/tests/tcmalloc_unittest.cc
diff options
context:
space:
mode:
authorAliaksey Kandratsenka <alkondratenko@gmail.com>2017-11-29 13:37:50 +0000
committerAliaksey Kandratsenka <alkondratenko@gmail.com>2017-11-29 21:44:49 +0000
commit89fe59c8318b2f8cec8ce00182dd24c357252c96 (patch)
treec89eb76bd039b21af837c157111302b37f4975a2 /src/tests/tcmalloc_unittest.cc
parenta29a0cf348e131d5b8ec26c39dabeac89cf13fcd (diff)
downloadgperftools-89fe59c8318b2f8cec8ce00182dd24c357252c96.tar.gz
Fix OOM handling in fast-path
Previous fast-path malloc implementation failed to arrange proper oom handling for operator new. I.e. operator new is supposed to call new handler and throw exception, which was not arranged in fast-path case. Fixed code now passes pointer for oom function to ThreadCache::FetchFromCentralCache which will call it in oom condition. Test is added to verify correct behavior. I've also updated some fast-path-related comments for more accuracy.
Diffstat (limited to 'src/tests/tcmalloc_unittest.cc')
-rw-r--r--src/tests/tcmalloc_unittest.cc66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/tests/tcmalloc_unittest.cc b/src/tests/tcmalloc_unittest.cc
index 59209d5..1f362f6 100644
--- a/src/tests/tcmalloc_unittest.cc
+++ b/src/tests/tcmalloc_unittest.cc
@@ -180,6 +180,37 @@ DECLARE_double(tcmalloc_release_rate);
DECLARE_int32(max_free_queue_size); // in debugallocation.cc
DECLARE_int64(tcmalloc_sample_parameter);
+struct OOMAbleSysAlloc : public SysAllocator {
+ SysAllocator *child;
+ int simulate_oom;
+
+ void* Alloc(size_t size, size_t* actual_size, size_t alignment) {
+ if (simulate_oom) {
+ return NULL;
+ }
+ return child->Alloc(size, actual_size, alignment);
+ }
+};
+
+static union {
+ char buf[sizeof(OOMAbleSysAlloc)];
+ void *ptr;
+} test_sys_alloc_space;
+
+static OOMAbleSysAlloc* get_test_sys_alloc() {
+ return reinterpret_cast<OOMAbleSysAlloc*>(&test_sys_alloc_space);
+}
+
+void setup_oomable_sys_alloc() {
+ SysAllocator *def = MallocExtension::instance()->GetSystemAllocator();
+
+ OOMAbleSysAlloc *alloc = get_test_sys_alloc();
+ new (alloc) OOMAbleSysAlloc;
+ alloc->child = def;
+
+ MallocExtension::instance()->SetSystemAllocator(alloc);
+}
+
namespace testing {
static const int FLAGS_numtests = 50000;
@@ -1130,12 +1161,47 @@ static void TestNAllocXAlignment() {
#endif // !DEBUGALLOCATION
+static int saw_new_handler_runs;
+static void* volatile oom_test_last_ptr;
+
+static void test_new_handler() {
+ get_test_sys_alloc()->simulate_oom = false;
+ void *ptr = oom_test_last_ptr;
+ oom_test_last_ptr = NULL;
+ ::operator delete[](ptr);
+ saw_new_handler_runs++;
+}
+
+static ATTRIBUTE_NOINLINE void TestNewOOMHandling() {
+ setup_oomable_sys_alloc();
+
+ std::new_handler old = std::set_new_handler(test_new_handler);
+ get_test_sys_alloc()->simulate_oom = true;
+
+ ASSERT_EQ(saw_new_handler_runs, 0);
+
+ for (int i = 0; i < 10240; i++) {
+ oom_test_last_ptr = new char [512];
+ ASSERT_NE(oom_test_last_ptr, NULL);
+ if (saw_new_handler_runs) {
+ break;
+ }
+ }
+
+ ASSERT_GE(saw_new_handler_runs, 1);
+
+ get_test_sys_alloc()->simulate_oom = false;
+ std::set_new_handler(old);
+}
+
static int RunAllTests(int argc, char** argv) {
// Optional argv[1] is the seed
AllocatorState rnd(argc > 1 ? atoi(argv[1]) : 100);
SetTestResourceLimit();
+ TestNewOOMHandling();
+
// TODO(odo): This test has been disabled because it is only by luck that it
// does not result in fragmentation. When tcmalloc makes an allocation which
// spans previously unused leaves of the pagemap it will allocate and fill in