Merge pull request #37 from Microsoft/invalid_pointer

Add an explicit invalid pointer type.
This commit is contained in:
Matthew Parkinson
2019-04-29 11:35:11 +01:00
committed by GitHub
2 changed files with 53 additions and 21 deletions

View File

@@ -6,29 +6,61 @@
namespace snmalloc
{
template<class T, uintptr_t Terminator = 0>
/**
* Invalid pointer class. This is similar to `std::nullptr_t`, but allows
* other values.
*/
template<uintptr_t Sentinel>
struct InvalidPointer
{
/**
* Equality comparison. Two invalid pointer values with the same sentinel
* are always the same, invalid pointer values with different sentinels are
* always different.
*/
template<uintptr_t OtherSentinel>
constexpr bool operator==(const InvalidPointer<OtherSentinel>&)
{
return Sentinel == OtherSentinel;
}
/**
* Equality comparison. Two invalid pointer values with the same sentinel
* are always the same, invalid pointer values with different sentinels are
* always different.
*/
template<uintptr_t OtherSentinel>
constexpr bool operator!=(const InvalidPointer<OtherSentinel>&)
{
return Sentinel != OtherSentinel;
}
/**
* Implicit conversion, creates a pointer with the value of the sentinel.
* On CHERI and other provenance-tracking systems, this is a
* provenance-free integer and so will trap if dereferenced, on other
* systems the sentinel should be a value in unmapped memory.
*/
template<typename T>
operator T*()
{
return reinterpret_cast<T*>(Sentinel);
}
};
template<class T, class Terminator = std::nullptr_t>
class DLList
{
private:
// Single point to perform this cast.
// Would like this to be a constexpr, but reinterpret cast is not allowed in
// constexpr.
static inline T* terminator()
{
return (T*)Terminator;
}
static_assert(
std::is_same<decltype(T::prev), T*>::value, "T->prev must be a T*");
static_assert(
std::is_same<decltype(T::next), T*>::value, "T->next must be a T*");
T* head = terminator();
T* head = Terminator();
public:
bool is_empty()
{
return head == terminator();
return head == Terminator();
}
T* get_head()
@@ -40,7 +72,7 @@ namespace snmalloc
{
T* item = head;
if (item != terminator())
if (item != Terminator())
remove(item);
return item;
@@ -53,9 +85,9 @@ namespace snmalloc
#endif
item->next = head;
item->prev = terminator();
item->prev = Terminator();
if (head != terminator())
if (head != Terminator())
head->prev = item;
head = item;
@@ -70,10 +102,10 @@ namespace snmalloc
debug_check_contains(item);
#endif
if (item->next != terminator())
if (item->next != Terminator())
item->next->prev = item->prev;
if (item->prev != terminator())
if (item->prev != Terminator())
item->prev->next = item->next;
else
head = item->next;
@@ -91,7 +123,7 @@ namespace snmalloc
while (curr != item)
{
assert(curr != terminator());
assert(curr != Terminator());
curr = curr->next;
}
#else
@@ -105,7 +137,7 @@ namespace snmalloc
debug_check();
T* curr = head;
while (curr != terminator())
while (curr != Terminator())
{
assert(curr != item);
curr = curr->next;
@@ -119,9 +151,9 @@ namespace snmalloc
{
#ifndef NDEBUG
T* item = head;
T* prev = terminator();
T* prev = Terminator();
while (item != terminator())
while (item != Terminator())
{
assert(item->prev == prev);
prev = item;

View File

@@ -19,7 +19,7 @@ namespace snmalloc
}
};
using SlabList = DLList<SlabLink, UINTPTR_MAX>;
using SlabList = DLList<SlabLink, InvalidPointer<UINTPTR_MAX>>;
static_assert(
sizeof(SlabLink) <= MIN_ALLOC_SIZE,