diff options
author | Aliaksey Kandratsenka <alkondratenko@gmail.com> | 2017-11-29 13:37:50 +0000 |
---|---|---|
committer | Aliaksey Kandratsenka <alkondratenko@gmail.com> | 2017-11-29 21:44:49 +0000 |
commit | 89fe59c8318b2f8cec8ce00182dd24c357252c96 (patch) | |
tree | c89eb76bd039b21af837c157111302b37f4975a2 /src/tests/tcmalloc_unittest.cc | |
parent | a29a0cf348e131d5b8ec26c39dabeac89cf13fcd (diff) | |
download | gperftools-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.cc | 66 |
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 |