diff --git a/src/mem/chunkmap.h b/src/mem/chunkmap.h index 8f00992..343e366 100644 --- a/src/mem/chunkmap.h +++ b/src/mem/chunkmap.h @@ -138,26 +138,23 @@ namespace snmalloc inline static ChunkmapPagemap* external_pagemap; public: - /** - * Constructor. Accesses the pagemap via the C ABI accessor and casts it to - * the expected type, failing in cases of ABI mismatch. - */ - ExternalGlobalPagemap() - { - const snmalloc::PagemapConfig* c; - external_pagemap = - ChunkmapPagemap::cast_to_pagemap(snmalloc_pagemap_global_get(&c), c); - if (!external_pagemap) - { - Pal::error("Incorrect ABI of global pagemap."); - } - } - /** * Returns the exported pagemap. + * Accesses the pagemap via the C ABI accessor and casts it to + * the expected type, failing in cases of ABI mismatch. */ static ChunkmapPagemap& pagemap() { + if (external_pagemap == nullptr) + { + const snmalloc::PagemapConfig* c = nullptr; + void* raw_pagemap = snmalloc_pagemap_global_get(&c); + external_pagemap = ChunkmapPagemap::cast_to_pagemap(raw_pagemap, c); + if (!external_pagemap) + { + Pal::error("Incorrect ABI of global pagemap."); + } + } return *external_pagemap; } }; diff --git a/src/mem/pagemap.h b/src/mem/pagemap.h index 5b78572..798c1c9 100644 --- a/src/mem/pagemap.h +++ b/src/mem/pagemap.h @@ -395,7 +395,7 @@ namespace snmalloc */ size_t index_for_address(uintptr_t p) { - return bits::align_down(static_cast(p) >> SHIFT, OS_PAGE_SIZE); + return (static_cast(p) >> SHIFT) % OS_PAGE_SIZE; } /** diff --git a/src/test/func/external_pagemap/external_pagemap.cc b/src/test/func/external_pagemap/external_pagemap.cc new file mode 100644 index 0000000..2e56be2 --- /dev/null +++ b/src/test/func/external_pagemap/external_pagemap.cc @@ -0,0 +1,30 @@ +#if defined(SNMALLOC_PASS_THROUGH) || defined(_WIN32) +// This test does not make sense with malloc pass-through, skip it. +// The malloc definitions are also currently incompatible with Windows headers +// so skip this test on Windows as well. +int main() +{ + return 0; +} +#else +# define SNMALLOC_EXPOSE_PAGEMAP 1 +# include + +int main() +{ + auto& p = ExternalGlobalPagemap::pagemap(); + auto& global = GlobalPagemap::pagemap(); + SNMALLOC_CHECK(&p == &global); + // Get a valid heap address + uintptr_t addr = reinterpret_cast(malloc(42)); + // Make this very strongly aligned + addr &= ~0xfffffULL; + void* page = p.page_for_address(addr); + SNMALLOC_CHECK(page == p.page_for_address(addr + 128)); + size_t idx = p.index_for_address(addr); + size_t idx2 = p.index_for_address(addr + SUPERSLAB_SIZE); + // If the pagemap ends up storing things that are not uint8_t, this test + // will need modifying. + SNMALLOC_CHECK(idx2 = ((idx + 1) % OS_PAGE_SIZE)); +} +#endif