Hardening access to meta data
Introduce a wrapper that ensure various fields of meta data, represent valid indexes into the the address space, and not beyond the current slab/superslab.
This commit is contained in:
@@ -32,6 +32,34 @@ namespace snmalloc
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper for wrapping values.
|
||||
*
|
||||
* Wraps on read. This allows code to trust the value is in range, even when
|
||||
* there is a memory corruption.
|
||||
**/
|
||||
template<size_t length, typename T>
|
||||
class Mod
|
||||
{
|
||||
static_assert(length == bits::next_pow2_const(length),
|
||||
"Must be a power of two.");
|
||||
|
||||
private:
|
||||
T value;
|
||||
|
||||
public:
|
||||
operator T()
|
||||
{
|
||||
return (T)(value & (length - 1));
|
||||
}
|
||||
|
||||
T& operator=(const T v)
|
||||
{
|
||||
value = v;
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t length, typename T>
|
||||
class ModArray
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/dllist.h"
|
||||
#include "../ds/helpers.h"
|
||||
#include "sizeclass.h"
|
||||
|
||||
namespace snmalloc
|
||||
@@ -51,11 +52,11 @@ namespace snmalloc
|
||||
// The terminal value in the free list, and the terminal value in
|
||||
// the SlabLink previous field will alias. The SlabLink uses ~0 for
|
||||
// its terminal value to be a valid terminal bump ptr.
|
||||
uint16_t head;
|
||||
Mod<SLAB_SIZE, uint16_t> head;
|
||||
// When a slab has free space it will be on the has space list for
|
||||
// that size class. We use an empty block in this slab to be the
|
||||
// doubly linked node into that size class's free list.
|
||||
uint16_t link;
|
||||
Mod<SLAB_SIZE, uint16_t> link;
|
||||
|
||||
uint8_t sizeclass;
|
||||
uint8_t next;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "allocslab.h"
|
||||
#include "metaslab.h"
|
||||
#include "../ds/helpers.h"
|
||||
#include <cstring>
|
||||
@@ -30,7 +31,7 @@ namespace snmalloc
|
||||
// are the relative offset to the next entry minus 1. This means that
|
||||
// all zeros is a list that chains through all the blocks, so the zero
|
||||
// initialised memory requires no more work.
|
||||
uint8_t head;
|
||||
Mod<SLAB_COUNT, uint8_t> head;
|
||||
|
||||
// Represents twice the number of full size slabs used
|
||||
// plus 1 for the short slab. i.e. using 3 slabs and the
|
||||
@@ -180,15 +181,16 @@ namespace snmalloc
|
||||
template<typename MemoryProvider>
|
||||
Slab* alloc_slab(uint8_t sizeclass, MemoryProvider& memory_provider)
|
||||
{
|
||||
Slab* slab = (Slab*)((size_t)this + ((size_t)head << SLAB_BITS));
|
||||
uint8_t h = head;
|
||||
Slab* slab = (Slab*)((size_t)this + ((size_t)h << SLAB_BITS));
|
||||
|
||||
uint8_t n = meta[head].next;
|
||||
uint8_t n = meta[h].next;
|
||||
|
||||
meta[head].head = get_slab_offset(sizeclass, false);
|
||||
meta[head].sizeclass = sizeclass;
|
||||
meta[head].link = SLABLINK_INDEX;
|
||||
meta[h].head = get_slab_offset(sizeclass, false);
|
||||
meta[h].sizeclass = sizeclass;
|
||||
meta[h].link = SLABLINK_INDEX;
|
||||
|
||||
head = head + n + 1;
|
||||
head = h + n + 1;
|
||||
used += 2;
|
||||
|
||||
if (decommit_strategy == DecommitAll)
|
||||
|
||||
Reference in New Issue
Block a user