Add some type safety to other pagemap accesses.

Introduce a descriptor for the pagemap config and check that the source
descriptor is compatible with the destination type.
This commit is contained in:
David Chisnall 2019-04-09 14:59:09 +01:00
Родитель 51fbdf3a44
Коммит a93f43fd2f
5 изменённых файлов: 79 добавлений и 2 удалений

Просмотреть файл

@ -10,6 +10,36 @@ namespace snmalloc
static constexpr size_t PAGEMAP_NODE_BITS = 16;
static constexpr size_t PAGEMAP_NODE_SIZE = 1ULL << PAGEMAP_NODE_BITS;
/**
* Structure describing the configuration of a pagemap. When querying a
* pagemap from a different instantiation of snmalloc, the pagemap is exposed
* as a `void*`. This structure allows the caller to check whether the
* pagemap is of the format that they expect.
*/
struct PagemapConfig
{
/**
* The version of the pagemap structure. This is always 1 in existing
* versions of snmalloc. This will be incremented every time the format
* changes in an incompatible way. Changes to the format may add fields to
* the end of this structure.
*/
uint32_t version;
/**
* Is this a flat pagemap? If this field is false, the pagemap is the
* hierarchical structure.
*/
bool is_flat_pagemap;
/**
* The number of bits of the address used to index into the pagemap.
*/
uint64_t pagemap_bits;
/**
* The size (in bytes) of a pagemap entry.
*/
size_t size_of_entry;
};
template<size_t GRANULARITY_BITS, typename T, T default_content>
class Pagemap
{
@ -168,6 +198,19 @@ namespace snmalloc
}
public:
static constexpr PagemapConfig config = {
1, false, GRANULARITY_BITS, sizeof(T)};
static Pagemap* cast_to_pagemap(void* pm, const PagemapConfig* c)
{
if (
(c->version != 1) || (c->is_flat_pagemap) ||
(c->pagemap_bits != GRANULARITY_BITS) ||
(c->size_of_entry != sizeof(T)) || (!std::is_integral_v<T>))
{
return nullptr;
}
return static_cast<Pagemap*>(pm);
}
/**
* Returns the index of a pagemap entry within a given page. This is used
* in code that propagates changes to the pagemap elsewhere.
@ -247,6 +290,20 @@ namespace snmalloc
std::atomic<T> top[ENTRIES];
public:
static constexpr PagemapConfig config = {
1, true, GRANULARITY_BITS, sizeof(T)};
static FlatPagemap* cast_to_pagemap(void* pm, PagemapConfig* c)
{
if (
(c->version != 1) || (!c->is_flat_pagemap) ||
(c->pagemap_bits != GRANULARITY_BITS) ||
(c->size_of_entry != sizeof(T)) || (!std::is_integral_v<T>))
{
return nullptr;
}
return static_cast<FlatPagemap*>(pm);
}
T get(void* p)
{
return top[(size_t)p >> SHIFT].load(std::memory_order_relaxed);
@ -268,4 +325,5 @@ namespace snmalloc
} while (length > 0);
}
};
}

Просмотреть файл

@ -206,8 +206,16 @@ extern "C"
}
#ifdef SNMALLOC_EXPOSE_PAGEMAP
SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(snmalloc_get_global_pagemap)(void)
SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(snmalloc_get_global_pagemap)(
PagemapConfig const** config)
{
if (config)
{
*config = &decltype(snmalloc::global_pagemap)::config;
assert(
decltype(snmalloc::global_pagemap)::cast_to_pagemap(
&snmalloc::global_pagemap, *config) == &snmalloc::global_pagemap);
}
return &snmalloc::global_pagemap;
}
#endif

Просмотреть файл

@ -4,6 +4,7 @@
#define USE_RESERVE_MULTIPLE 1
#define NO_BOOTSTRAP_ALLOCATOR
#define IS_ADDRESS_SPACE_CONSTRAINED
#define SNMALLOC_EXPOSE_PAGEMAP
#define SNMALLOC_NAME_MANGLE(a) enclave_##a
// Redefine the namespace, so we can have two versions.
#define snmalloc snmalloc_enclave

Просмотреть файл

@ -1,6 +1,7 @@
#undef IS_ADDRESS_SPACE_CONSTRAINED
#define SNMALLOC_NAME_MANGLE(a) host_##a
#define NO_BOOTSTRAP_ALLOCATOR
#define SNMALLOC_EXPOSE_PAGEMAP
// Redefine the namespace, so we can have two versions.
#define snmalloc snmalloc_host
#include "../../../override/malloc.cc"
#include "../../../override/malloc.cc"

Просмотреть файл

@ -32,6 +32,11 @@ extern "C" void host_free(void*);
extern "C" void* enclave_malloc(size_t);
extern "C" void enclave_free(void*);
extern "C" void*
enclave_snmalloc_get_global_pagemap(snmalloc::PagemapConfig const**);
extern "C" void*
host_snmalloc_get_global_pagemap(snmalloc::PagemapConfig const**);
using namespace snmalloc;
int main()
{
@ -42,6 +47,10 @@ int main()
oe_end = (uint8_t*)oe_base + size;
std::cout << "Allocated region " << oe_base << " - " << oe_end << std::endl;
// Call these functions to trigger asserts if the cast-to-self doesn't work.
enclave_snmalloc_get_global_pagemap(nullptr);
host_snmalloc_get_global_pagemap(nullptr);
auto a = host_malloc(128);
auto b = enclave_malloc(128);