Make the pagemap global typed.

The pagemap global is now an inline static of a template class, so that
we will see different symbols for the different types.

Issue #84 showed that it's possible to compile two compilation units
with different pagemaps, link them together, and have them attempt to
interpret the global pagemap as two different types.  This change should
make that impossible.

Also make the `pagemap()` function static so that it can be used from
static functions, avoiding other things that directly reference the
global pagemap.
This commit is contained in:
David Chisnall
2019-08-13 13:26:07 +01:00
committed by David Chisnall
parent 2efa4b14fb
commit d2dc653af2
2 changed files with 29 additions and 14 deletions

View File

@@ -55,24 +55,40 @@ namespace snmalloc
FlatPagemap<SUPERSLAB_BITS, uint8_t>,
Pagemap<SUPERSLAB_BITS, uint8_t, 0>>;
HEADER_GLOBAL SuperslabPagemap global_pagemap;
/**
* Mixin used by `SuperslabMap` to directly access the pagemap via a global
* variable. This should be used from within the library or program that
* owns the pagemap.
*
* This class makes the global pagemap a static field so that its name
* includes the type mangling. If two compilation units try to instantiate
* two different types of pagemap then they will see two distinct pagemaps.
* This will prevent allocating with one and freeing with the other (because
* the memory will show up as not owned by any allocator in the other
* compilation unit) but will prevent the same memory being interpreted as
* having two different types.
*/
struct GlobalPagemap
template<typename T>
class GlobalPagemapTemplate
{
/**
* The global pagemap variable. The name of this symbol will include the
* type of `T`.
*/
inline static T global_pagemap;
public:
/**
* Returns the pagemap.
*/
SuperslabPagemap& pagemap()
static SuperslabPagemap& pagemap()
{
return global_pagemap;
}
};
using GlobalPagemap = GlobalPagemapTemplate<SuperslabPagemap>;
/**
* Optionally exported function that accesses the global pagemap provided by
* a shared library.
@@ -91,7 +107,7 @@ namespace snmalloc
/**
* A pointer to the pagemap.
*/
SuperslabPagemap* external_pagemap;
inline static SuperslabPagemap* external_pagemap;
public:
/**
@@ -110,7 +126,7 @@ namespace snmalloc
/**
* Returns the exported pagemap.
*/
SuperslabPagemap& pagemap()
static SuperslabPagemap& pagemap()
{
return *external_pagemap;
}
@@ -531,7 +547,7 @@ namespace snmalloc
error("Unsupported");
UNUSED(p);
#else
uint8_t size = global_pagemap.get(address_cast(p));
uint8_t size = PageMap::pagemap().get(address_cast(p));
Superslab* super = Superslab::get(p);
if (size == PMSuperslab)
@@ -561,7 +577,7 @@ namespace snmalloc
{
// This is a large alloc redirect.
ss = ss - (1ULL << (size - 64));
size = global_pagemap.get(ss);
size = PageMap::pagemap().get(ss);
}
if (size == 0)
@@ -593,7 +609,7 @@ namespace snmalloc
static size_t alloc_size(void* p)
{
// This must be called on an external pointer.
size_t size = global_pagemap.get(address_cast(p));
size_t size = PageMap::pagemap().get(address_cast(p));
if (size == 0)
{

View File

@@ -210,14 +210,13 @@ extern "C"
SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(snmalloc_pagemap_global_get)(
PagemapConfig const** config)
{
auto& pm = GlobalPagemap::pagemap();
if (config)
{
*config = &decltype(snmalloc::global_pagemap)::config;
assert(
decltype(snmalloc::global_pagemap)::cast_to_pagemap(
&snmalloc::global_pagemap, *config) == &snmalloc::global_pagemap);
*config = &SuperslabPagemap::config;
assert(SuperslabPagemap::cast_to_pagemap(&pm, *config) == &pm);
}
return &snmalloc::global_pagemap;
return &pm;
}
#endif