Merge pull request #97 from microsoft/memory_leak

Memory leak
This commit is contained in:
Matthew Parkinson
2019-11-14 14:48:11 +00:00
committed by GitHub
2 changed files with 73 additions and 22 deletions

View File

@@ -875,6 +875,61 @@ namespace snmalloc
#endif
}
/**
* If result parameter is non-null, then false is assigned into the
* the location pointed to by result if this allocator is non-empty.
*
* If result pointer is null, then this code raises a Pal::error on the
* particular check that fails, if any do fail.
**/
void debug_is_empty(bool* result)
{
auto test = [&result](auto& queue) {
if (!queue.is_empty())
{
if (result != nullptr)
*result = false;
else
error("debug_is_empty: found non-empty allocator");
}
};
// Destroy the message queue so that it has no stub message.
Remote* p = message_queue().destroy();
while (p != nullptr)
{
Remote* n = p->non_atomic_next;
handle_dealloc_remote(p);
p = n;
}
for (size_t i = 0; i < NUM_SMALL_CLASSES; i++)
{
auto prev = small_fast_free_lists[i].value;
small_fast_free_lists[i].value = nullptr;
while (prev != nullptr)
{
auto n = Metaslab::follow_next(prev);
dealloc(remove_cache_friendly_offset(prev, i));
prev = n;
}
test(small_classes[i]);
}
for (auto& medium_class : medium_classes)
{
test(medium_class);
}
test(super_available);
test(super_only_short_available);
// Place the static stub message on the queue.
init_message_queue();
}
template<Boundary location>
static uintptr_t
external_pointer(void* p, sizeclass_t sizeclass, size_t end_point)
@@ -1084,7 +1139,12 @@ namespace snmalloc
SNMALLOC_ASSUME(size <= SLAB_SIZE);
sizeclass_t sizeclass = size_to_sizeclass(size);
return small_alloc_inner<zero_mem, allow_reserve>(sizeclass);
}
template<ZeroMem zero_mem, AllowReserve allow_reserve>
SNMALLOC_FAST_PATH void* small_alloc_inner(sizeclass_t sizeclass)
{
assert(sizeclass < NUM_SMALL_CLASSES);
auto& fl = small_fast_free_lists[sizeclass];
void* head = fl.value;
@@ -1097,7 +1157,7 @@ namespace snmalloc
void* p = remove_cache_friendly_offset(head, sizeclass);
if constexpr (zero_mem == YesZero)
{
large_allocator.memory_provider.zero(p, size);
large_allocator.memory_provider.zero(p, sizeclass_to_size(sizeclass));
}
return p;
}
@@ -1111,7 +1171,7 @@ namespace snmalloc
if (void* replacement = Replacement(this))
{
return reinterpret_cast<Allocator*>(replacement)
->template small_alloc_slow<zero_mem, allow_reserve>(sizeclass);
->template small_alloc_inner<zero_mem, allow_reserve>(sizeclass);
}
stats().sizeclass_alloc(sizeclass);

View File

@@ -120,32 +120,18 @@ namespace snmalloc
auto* alloc = Parent::iterate();
bool done = false;
bool okay = true;
size_t non_empty_count = 0;
while (!done)
{
done = true;
alloc = Parent::iterate();
non_empty_count = 0;
okay = true;
while (alloc != nullptr)
{
// Destroy the message queue so that it has no stub message.
Remote* p = alloc->message_queue().destroy();
while (p != nullptr)
{
Remote* next = p->non_atomic_next;
alloc->handle_dealloc_remote(p);
p = next;
}
// Check that the allocator has freed all memory.
if (!alloc->stats().is_empty())
non_empty_count++;
// Place the static stub message on the queue.
alloc->init_message_queue();
alloc->debug_is_empty(&okay);
// Post all remotes, including forwarded ones. If any allocator posts,
// repeat the loop.
@@ -162,13 +148,18 @@ namespace snmalloc
if (result != nullptr)
{
*result = non_empty_count == 0;
*result = okay;
return;
}
if (non_empty_count != 0)
if (!okay)
{
error("debug_check_empty: found non-empty allocators");
alloc = Parent::iterate();
while (alloc != nullptr)
{
alloc->debug_is_empty(nullptr);
alloc = Parent::iterate(alloc);
}
}
#else
UNUSED(result);