NFC: Further disentangle chunkmap and pagemap

- Make GlobalPagemapTemplate and ExternalGlobalPagemap generic in the type of
  the pagemap they're encapsulating.

  We're going to want to use these for other kinds of pagemaps in the near
  future.

- Rename snmalloc_pagemap_global_get to snmalloc_chunkmap_global_get.

- Rename GlobalPagemap to GlobalChunkmap.
This commit is contained in:
Nathaniel Filardo
2021-01-08 18:05:45 +00:00
committed by Matthew Parkinson
parent 8da12f5af8
commit 6250428c3d
5 changed files with 87 additions and 81 deletions

View File

@@ -83,81 +83,14 @@ namespace snmalloc
FlatPagemap<SUPERSLAB_BITS, uint8_t>,
Pagemap<SUPERSLAB_BITS, uint8_t, 0>>;
/**
* Mixin used by `ChunkMap` 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.
*/
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.
*/
static ChunkmapPagemap& pagemap()
{
return global_pagemap;
}
};
using GlobalPagemap = GlobalPagemapTemplate<ChunkmapPagemap>;
using GlobalChunkmap = GlobalPagemapTemplate<ChunkmapPagemap>;
/**
* Optionally exported function that accesses the global pagemap provided by
* a shared library.
* Optionally exported function that accesses the global chunkmap pagemap
* provided by a shared library.
*/
extern "C" void* snmalloc_pagemap_global_get(snmalloc::PagemapConfig const**);
/**
* Mixin used by `ChunkMap` to access the global pagemap via a
* type-checked C interface. This should be used when another library (e.g.
* your C standard library) uses snmalloc and you wish to use a different
* configuration in your program or library, but wish to share a pagemap so
* that either version can deallocate memory.
*/
class ExternalGlobalPagemap
{
/**
* A pointer to the pagemap.
*/
inline static ChunkmapPagemap* external_pagemap;
public:
/**
* 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;
}
};
extern "C" void*
snmalloc_chunkmap_global_get(snmalloc::PagemapConfig const**);
/**
* Class that defines an interface to the pagemap. This is provided to
@@ -165,7 +98,7 @@ namespace snmalloc
* implementation (for example, to move pagemap updates to a different
* protection domain).
*/
template<typename PagemapProvider = GlobalPagemap>
template<typename PagemapProvider = GlobalChunkmap>
struct DefaultChunkMap
{
/**

View File

@@ -409,4 +409,74 @@ namespace snmalloc
reinterpret_cast<uintptr_t>(&top[p >> SHIFT]) & ~(OS_PAGE_SIZE - 1));
}
};
/**
* Mixin used by `ChunkMap` and other `PageMap` consumers 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.
*/
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.
*/
static T& pagemap()
{
return global_pagemap;
}
};
/**
* Mixin used by `ChunkMap` and other `PageMap` consumers to access the global
* pagemap via a type-checked C interface. This should be used when another
* library (e.g. your C standard library) uses snmalloc and you wish to use a
* different configuration in your program or library, but wish to share a
* pagemap so that either version can deallocate memory.
*/
template<typename T, void* (*raw_get)(const PagemapConfig**)>
class ExternalGlobalPagemapTemplate
{
/**
* A pointer to the pagemap.
*/
inline static T* external_pagemap;
public:
/**
* 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 T& pagemap()
{
if (external_pagemap == nullptr)
{
const snmalloc::PagemapConfig* c = nullptr;
void* raw_pagemap = raw_get(&c);
external_pagemap = T::cast_to_pagemap(raw_pagemap, c);
if (!external_pagemap)
{
Pal::error("Incorrect ABI of global pagemap.");
}
}
return *external_pagemap;
}
};
} // namespace snmalloc

View File

@@ -221,10 +221,10 @@ extern "C"
* this function to the correct type. This allows us to preserve some
* semblance of ABI safety via a pure C API.
*/
SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(snmalloc_pagemap_global_get)(
SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(snmalloc_chunkmap_global_get)(
PagemapConfig const** config)
{
auto& pm = GlobalPagemap::pagemap();
auto& pm = GlobalChunkmap::pagemap();
if (config)
{
*config = &ChunkmapPagemap::config;

View File

@@ -10,10 +10,13 @@ int main()
# define SNMALLOC_EXPOSE_PAGEMAP 1
# include <override/malloc.cc>
using ExternalChunkmap =
ExternalGlobalPagemapTemplate<ChunkmapPagemap, snmalloc_chunkmap_global_get>;
int main()
{
auto& p = ExternalGlobalPagemap::pagemap();
auto& global = GlobalPagemap::pagemap();
auto& p = ExternalChunkmap::pagemap();
auto& global = GlobalChunkmap::pagemap();
SNMALLOC_CHECK(&p == &global);
// Get a valid heap address
uintptr_t addr = reinterpret_cast<uintptr_t>(malloc(42));

View File

@@ -24,9 +24,9 @@ extern "C" void* enclave_malloc(size_t);
extern "C" void enclave_free(void*);
extern "C" void*
enclave_snmalloc_pagemap_global_get(snmalloc::PagemapConfig const**);
enclave_snmalloc_chunkmap_global_get(snmalloc::PagemapConfig const**);
extern "C" void*
host_snmalloc_pagemap_global_get(snmalloc::PagemapConfig const**);
host_snmalloc_chunkmap_global_get(snmalloc::PagemapConfig const**);
using namespace snmalloc;
int main()
@@ -47,8 +47,8 @@ int main()
// Call these functions to trigger asserts if the cast-to-self doesn't work.
const PagemapConfig* c;
enclave_snmalloc_pagemap_global_get(&c);
host_snmalloc_pagemap_global_get(&c);
enclave_snmalloc_chunkmap_global_get(&c);
host_snmalloc_chunkmap_global_get(&c);
auto a = host_malloc(128);
auto b = enclave_malloc(128);