Add validate to freelist::Builder
The free list builder in a checked build will only validate entries when they are removed. This commit adds a validate method, so they can be checked during teardown. This means that programs that leak memory will still fail if the free list has become corrupt.
This commit is contained in:
committed by
Matthew Parkinson
parent
93bb037c64
commit
6db9a2f0e2
@@ -330,12 +330,31 @@ namespace snmalloc
|
||||
return chunk_record;
|
||||
}
|
||||
|
||||
template<bool check_slabs = false>
|
||||
SNMALLOC_SLOW_PATH void dealloc_local_slabs(sizeclass_t sizeclass)
|
||||
{
|
||||
// Return unused slabs of sizeclass_t back to global allocator
|
||||
alloc_classes[sizeclass].queue.filter([this, sizeclass](Metaslab* meta) {
|
||||
auto domesticate =
|
||||
[this](freelist::QueuePtr p) SNMALLOC_FAST_PATH_LAMBDA {
|
||||
auto res =
|
||||
capptr_domesticate<SharedStateHandle>(backend_state_ptr(), p);
|
||||
#ifdef SNMALLOC_TRACING
|
||||
if (res.unsafe_ptr() != p.unsafe_ptr())
|
||||
printf(
|
||||
"Domesticated %p to %p!\n", p.unsafe_ptr(), res.unsafe_ptr());
|
||||
#endif
|
||||
return res;
|
||||
};
|
||||
|
||||
if (meta->needed() != 0)
|
||||
{
|
||||
if (check_slabs)
|
||||
{
|
||||
meta->free_queue.validate(entropy.get_free_list_key(), domesticate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
alloc_classes[sizeclass].length--;
|
||||
alloc_classes[sizeclass].unused--;
|
||||
@@ -789,7 +808,7 @@ namespace snmalloc
|
||||
// We may now have unused slabs, return to the global allocator.
|
||||
for (sizeclass_t sizeclass = 0; sizeclass < NUM_SIZECLASSES; sizeclass++)
|
||||
{
|
||||
dealloc_local_slabs(sizeclass);
|
||||
dealloc_local_slabs<true>(sizeclass);
|
||||
}
|
||||
|
||||
return posted;
|
||||
|
||||
@@ -116,6 +116,13 @@ namespace snmalloc
|
||||
template<SNMALLOC_CONCEPT(capptr::ConceptBound) BQueue>
|
||||
class T
|
||||
{
|
||||
template<
|
||||
bool,
|
||||
bool,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound),
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound)>
|
||||
friend class Builder;
|
||||
|
||||
friend class Object;
|
||||
|
||||
union
|
||||
@@ -699,6 +706,40 @@ namespace snmalloc
|
||||
init();
|
||||
return {first, last};
|
||||
}
|
||||
|
||||
template<typename Domesticator>
|
||||
SNMALLOC_FAST_PATH void
|
||||
validate(const FreeListKey& key, Domesticator domesticate)
|
||||
{
|
||||
#ifdef SNMALLOC_CHECK_CLIENT
|
||||
for (uint32_t i = 0; i < LENGTH; i++)
|
||||
{
|
||||
if (&head[i] == end[i])
|
||||
{
|
||||
SNMALLOC_ASSERT(length[i] == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t count = 1;
|
||||
auto curr = read_head(i, key);
|
||||
auto prev = get_fake_signed_prev(i, key);
|
||||
while (true)
|
||||
{
|
||||
curr->check_prev(prev);
|
||||
if (address_cast(&(curr->next_object)) == address_cast(end[i]))
|
||||
break;
|
||||
count++;
|
||||
auto next = curr->read_next(key, domesticate);
|
||||
prev = signed_prev(address_cast(curr), address_cast(next), key);
|
||||
curr = next;
|
||||
}
|
||||
SNMALLOC_ASSERT(count == length[i]);
|
||||
}
|
||||
#else
|
||||
UNUSED(key);
|
||||
UNUSED(domesticate);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace freelist
|
||||
} // namespace snmalloc
|
||||
|
||||
Reference in New Issue
Block a user