TEST_F(HeapWalkerTest, live) { const int from_buffer_entries = 4; const int to_buffer_bytes = 16; for (int i = 0; i < from_buffer_entries; i++) { for (int j = 0; j < to_buffer_bytes; j++) { void* buffer1[from_buffer_entries]{}; char buffer2[to_buffer_bytes]{}; buffer1[i] = &buffer2[j]; HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); heap_walker.Root(buffer_begin(buffer1), buffer_end(buffer1)); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = SIZE_MAX; size_t leaked_bytes = SIZE_MAX; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(0U, num_leaks); EXPECT_EQ(0U, leaked_bytes); EXPECT_EQ(0U, leaked.size()); } } }
TEST_F(HeapWalkerTest, unaligned) { const int from_buffer_entries = 4; const int to_buffer_bytes = 16; void* buffer1[from_buffer_entries]{}; char buffer2[to_buffer_bytes]{}; buffer1[1] = &buffer2; for (unsigned int i = 0; i < sizeof(uintptr_t); i++) { for (unsigned int j = 0; j < sizeof(uintptr_t); j++) { HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); heap_walker.Root(buffer_begin(buffer1) + i, buffer_end(buffer1) - j); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = SIZE_MAX; size_t leaked_bytes = SIZE_MAX; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(0U, num_leaks); EXPECT_EQ(0U, leaked_bytes); EXPECT_EQ(0U, leaked.size()); } } }
void NameValueTable::leak() { m_elms = 0; m_tabMask = 0; req::free(m_table); m_table = nullptr; assert(leaked()); }
NameValueTable::~NameValueTable() { if (leaked()) return; for (Elm* elm = &m_table[m_tabMask]; elm != &m_table[-1]; --elm) { if (elm->m_name) { decRefStr(const_cast<StringData*>(elm->m_name)); if (elm->m_tv.m_type != kNamedLocalDataType) { tvRefcountedDecRef(elm->m_tv); } } } req::free(m_table); }
TEST_F(HeapWalkerTest, leak) { void* buffer1[16]{}; char buffer2[16]{}; buffer1[0] = &buffer2[0] - sizeof(void*); buffer1[1] = &buffer2[15] + sizeof(void*); HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = 0; size_t leaked_bytes = 0; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(1U, num_leaks); EXPECT_EQ(16U, leaked_bytes); ASSERT_EQ(1U, leaked.size()); EXPECT_EQ(buffer_begin(buffer2), leaked[0].begin); EXPECT_EQ(buffer_end(buffer2), leaked[0].end); }
TEST_F(HeapWalkerTest, cycle) { void* buffer1; void* buffer2; buffer1 = &buffer2; buffer2 = &buffer1; HeapWalker heap_walker(heap_); heap_walker.Allocation(buffer_begin(buffer1), buffer_end(buffer1)); heap_walker.Allocation(buffer_begin(buffer2), buffer_end(buffer2)); ASSERT_EQ(true, heap_walker.DetectLeaks()); allocator::vector<Range> leaked(heap_); size_t num_leaks = 0; size_t leaked_bytes = 0; ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes)); EXPECT_EQ(2U, num_leaks); EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes); ASSERT_EQ(2U, leaked.size()); }