Fix bug in pagemap when index has many levels

The pagemap was double incrementing the index level.  This did not
exhibit in any use case of the pagemap as it only used 0 or 1 level of
intermediate index for all current use cases.

This commit fixes the bug, and adds a test that uses the pagemap in a
different configuration that has multiple levels of intermediate index
node.
This commit is contained in:
Matthew Parkinson
2020-09-24 09:40:54 +01:00
committed by Matthew Parkinson
parent e615c33f7a
commit f89f78ad46
2 changed files with 81 additions and 16 deletions

View File

@@ -184,25 +184,35 @@ namespace snmalloc
size_t shift = TOPLEVEL_SHIFT;
std::atomic<PagemapEntry*>* e = &top[ix];
for (size_t i = 0; i < INDEX_LEVELS; i++)
// This is effectively a
// for (size_t i = 0; i < INDEX_LEVELS; i++)
// loop, but uses constexpr to guarantee optimised version
// where the INDEX_LEVELS in {0,1}.
if constexpr (INDEX_LEVELS != 0)
{
PagemapEntry* value = get_node<create_addr>(e, result);
if (unlikely(!result))
return {nullptr, 0};
shift -= BITS_PER_INDEX_LEVEL;
ix = (static_cast<size_t>(addr) >> shift) & ENTRIES_MASK;
e = &value->entries[ix];
if constexpr (INDEX_LEVELS == 1)
size_t i = 0;
while (true)
{
UNUSED(i);
break;
}
i++;
PagemapEntry* value = get_node<create_addr>(e, result);
if (unlikely(!result))
return {nullptr, 0};
if (i == INDEX_LEVELS)
break;
shift -= BITS_PER_INDEX_LEVEL;
ix = (static_cast<size_t>(addr) >> shift) & ENTRIES_MASK;
e = &value->entries[ix];
if constexpr (INDEX_LEVELS == 1)
{
UNUSED(i);
break;
}
else
{
i++;
if (i == INDEX_LEVELS)
break;
}
}
}
Leaf* leaf = reinterpret_cast<Leaf*>(get_node<create_addr>(e, result));