RFC: Hide CapPtr constructor

Expose a static CapPtr<T,B>::unsafe_from() and use that everywhere instead
(though continue to allow implicit and explicit construction of CapPtr from
nullptr).
This commit is contained in:
Nathaniel Wesley Filardo
2022-06-06 17:40:25 +01:00
committed by Nathaniel Filardo
parent 41128a3387
commit f41bb321f7
16 changed files with 74 additions and 47 deletions

View File

@@ -212,7 +212,8 @@ namespace snmalloc
"capptr_bound must preserve non-spatial CapPtr dimensions");
UNUSED(size);
return CapPtr<T, BOut>(a.template as_static<T>().unsafe_ptr());
return CapPtr<T, BOut>::unsafe_from(
a.template as_static<T>().unsafe_ptr());
}
};
} // namespace snmalloc

View File

@@ -86,7 +86,7 @@ namespace snmalloc
}
void* pb = __builtin_cheri_bounds_set_exact(a.unsafe_ptr(), size);
return CapPtr<T, BOut>(static_cast<T*>(pb));
return CapPtr<T, BOut>::unsafe_from(static_cast<T*>(pb));
}
};
} // namespace snmalloc

View File

@@ -34,7 +34,8 @@ namespace snmalloc
inline CapPtr<void, bounds>
pointer_offset(CapPtr<T, bounds> base, size_t diff)
{
return CapPtr<void, bounds>(pointer_offset(base.unsafe_ptr(), diff));
return CapPtr<void, bounds>::unsafe_from(
pointer_offset(base.unsafe_ptr(), diff));
}
/**
@@ -51,7 +52,8 @@ namespace snmalloc
inline CapPtr<void, bounds>
pointer_offset_signed(CapPtr<T, bounds> base, ptrdiff_t diff)
{
return CapPtr<void, bounds>(pointer_offset_signed(base.unsafe_ptr(), diff));
return CapPtr<void, bounds>::unsafe_from(
pointer_offset_signed(base.unsafe_ptr(), diff));
}
/**
@@ -137,7 +139,8 @@ namespace snmalloc
SNMALLOC_CONCEPT(capptr::ConceptBound) bounds>
inline CapPtr<T, bounds> pointer_align_down(CapPtr<void, bounds> p)
{
return CapPtr<T, bounds>(pointer_align_down<alignment, T>(p.unsafe_ptr()));
return CapPtr<T, bounds>::unsafe_from(
pointer_align_down<alignment, T>(p.unsafe_ptr()));
}
template<size_t alignment>
@@ -174,7 +177,8 @@ namespace snmalloc
SNMALLOC_CONCEPT(capptr::ConceptBound) bounds>
inline CapPtr<T, bounds> pointer_align_up(CapPtr<void, bounds> p)
{
return CapPtr<T, bounds>(pointer_align_up<alignment, T>(p.unsafe_ptr()));
return CapPtr<T, bounds>::unsafe_from(
pointer_align_up<alignment, T>(p.unsafe_ptr()));
}
template<size_t alignment>
@@ -204,7 +208,8 @@ namespace snmalloc
inline CapPtr<T, bounds>
pointer_align_down(CapPtr<void, bounds> p, size_t alignment)
{
return CapPtr<T, bounds>(pointer_align_down<T>(p.unsafe_ptr(), alignment));
return CapPtr<T, bounds>::unsafe_from(
pointer_align_down<T>(p.unsafe_ptr(), alignment));
}
/**
@@ -228,7 +233,8 @@ namespace snmalloc
inline CapPtr<T, bounds>
pointer_align_up(CapPtr<void, bounds> p, size_t alignment)
{
return CapPtr<T, bounds>(pointer_align_up<T>(p.unsafe_ptr(), alignment));
return CapPtr<T, bounds>::unsafe_from(
pointer_align_up<T>(p.unsafe_ptr(), alignment));
}
/**

View File

@@ -140,12 +140,12 @@ namespace snmalloc
Pagemap::set_metaentry(address_cast(alloc), size, t);
local_state.get_meta_range().dealloc_range(
capptr::Chunk<void>(&slab_metadata), sizeof(SlabMetadata));
capptr::Chunk<void>::unsafe_from(&slab_metadata), sizeof(SlabMetadata));
// On non-CHERI platforms, we don't need to re-derive to get a pointer to
// the chunk. On CHERI platforms this will need to be stored in the
// SlabMetadata or similar.
capptr::Chunk<void> chunk{alloc.unsafe_ptr()};
auto chunk = capptr::Chunk<void>::unsafe_from(alloc.unsafe_ptr());
local_state.object_range.dealloc_range(chunk, size);
}

View File

@@ -78,7 +78,7 @@ namespace snmalloc
// Push memory into the global range.
range_to_pow_2_blocks<MIN_CHUNK_BITS>(
capptr::Chunk<void>(heap_base),
capptr::Chunk<void>::unsafe_from(heap_base),
heap_length,
[&](capptr::Chunk<void> p, size_t sz, bool) {
typename LocalState::GlobalR g;
@@ -108,8 +108,8 @@ namespace snmalloc
return CapPtr<
T,
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>(
p.unsafe_ptr());
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>::
unsafe_from(p.unsafe_ptr());
}
};
}

View File

@@ -262,8 +262,9 @@ namespace snmalloc
{
range_to_pow_2_blocks<MIN_CHUNK_BITS>(
base, length, [this](capptr::Chunk<void> base, size_t align, bool) {
auto overflow = capptr::Chunk<void>(reinterpret_cast<void*>(
buddy_large.add_block(base.unsafe_uintptr(), align)));
auto overflow =
capptr::Chunk<void>::unsafe_from(reinterpret_cast<void*>(
buddy_large.add_block(base.unsafe_uintptr(), align)));
dealloc_overflow(overflow);
});
@@ -358,7 +359,7 @@ namespace snmalloc
return nullptr;
}
auto result = capptr::Chunk<void>(
auto result = capptr::Chunk<void>::unsafe_from(
reinterpret_cast<void*>(buddy_large.remove_block(size)));
if (result != nullptr)
@@ -381,8 +382,9 @@ namespace snmalloc
}
}
auto overflow = capptr::Chunk<void>(reinterpret_cast<void*>(
buddy_large.add_block(base.unsafe_uintptr(), size)));
auto overflow =
capptr::Chunk<void>::unsafe_from(reinterpret_cast<void*>(
buddy_large.add_block(base.unsafe_uintptr(), size)));
dealloc_overflow(overflow);
}
};

View File

@@ -28,8 +28,8 @@ namespace snmalloc
if constexpr (pal_supports<AlignedAllocation, PAL>)
{
SNMALLOC_ASSERT(size >= PAL::minimum_alloc_size);
auto result =
capptr::Chunk<void>(PAL::template reserve_aligned<false>(size));
auto result = capptr::Chunk<void>::unsafe_from(
PAL::template reserve_aligned<false>(size));
#ifdef SNMALLOC_TRACING
message<1024>("Pal range alloc: {} ({})", result.unsafe_ptr(), size);
@@ -38,7 +38,7 @@ namespace snmalloc
}
else
{
auto result = capptr::Chunk<void>(PAL::reserve(size));
auto result = capptr::Chunk<void>::unsafe_from(PAL::reserve(size));
#ifdef SNMALLOC_TRACING
message<1024>("Pal range alloc: {} ({})", result.unsafe_ptr(), size);

View File

@@ -33,7 +33,7 @@ namespace snmalloc
{
SNMALLOC_ASSERT((address_cast(r) & MASK) == 0);
if (r == nullptr)
*ptr = capptr::Chunk<FreeChunk>(
*ptr = capptr::Chunk<FreeChunk>::unsafe_from(
reinterpret_cast<FreeChunk*>((*ptr).unsafe_uintptr() & MASK));
else
// Preserve lower bit.
@@ -71,7 +71,8 @@ namespace snmalloc
if (new_is_red)
{
if (old_addr == nullptr)
*r = capptr::Chunk<FreeChunk>(reinterpret_cast<FreeChunk*>(MASK));
*r = capptr::Chunk<FreeChunk>::unsafe_from(
reinterpret_cast<FreeChunk*>(MASK));
else
*r = pointer_offset(old_addr, MASK).template as_static<FreeChunk>();
}

View File

@@ -283,6 +283,7 @@ namespace snmalloc
constexpr SNMALLOC_FAST_PATH CapPtr() : CapPtr(nullptr) {}
private:
/**
* all other constructions must be explicit
*
@@ -302,13 +303,25 @@ namespace snmalloc
# pragma warning(pop)
#endif
public:
/**
* The CapPtr constructor is not sufficiently intimidating, given that it
* can be used to break annotation correctness. Expose it with a better
* name.
*/
static constexpr SNMALLOC_FAST_PATH CapPtr unsafe_from(T* p)
{
return CapPtr<T, bounds>(p);
}
/**
* Allow static_cast<>-s that preserve bounds but vary the target type.
*/
template<typename U>
[[nodiscard]] SNMALLOC_FAST_PATH CapPtr<U, bounds> as_static() const
{
return CapPtr<U, bounds>(static_cast<U*>(this->unsafe_capptr));
return CapPtr<U, bounds>::unsafe_from(
static_cast<U*>(this->unsafe_capptr));
}
[[nodiscard]] SNMALLOC_FAST_PATH CapPtr<void, bounds> as_void() const
@@ -322,7 +335,8 @@ namespace snmalloc
template<typename U>
[[nodiscard]] SNMALLOC_FAST_PATH CapPtr<U, bounds> as_reinterpret() const
{
return CapPtr<U, bounds>(reinterpret_cast<U*>(this->unsafe_capptr));
return CapPtr<U, bounds>::unsafe_from(
reinterpret_cast<U*>(this->unsafe_capptr));
}
SNMALLOC_FAST_PATH bool operator==(const CapPtr& rhs) const
@@ -396,7 +410,7 @@ namespace snmalloc
inline SNMALLOC_FAST_PATH capptr::Alloc<T>
capptr_chunk_is_alloc(capptr::ChunkUser<T> p)
{
return capptr::Alloc<T>(p.unsafe_ptr());
return capptr::Alloc<T>::unsafe_from(p.unsafe_ptr());
}
/**
@@ -426,7 +440,7 @@ namespace snmalloc
static inline SNMALLOC_FAST_PATH capptr::AllocWild<void>
capptr_from_client(void* p)
{
return capptr::AllocWild<void>(p);
return capptr::AllocWild<void>::unsafe_from(p);
}
/**
@@ -440,8 +454,8 @@ namespace snmalloc
{
return CapPtr<
T,
typename B::template with_wildness<capptr::dimension::Wildness::Wild>>(
p.unsafe_ptr());
typename B::template with_wildness<capptr::dimension::Wildness::Wild>>::
unsafe_from(p.unsafe_ptr());
}
/**
@@ -490,7 +504,7 @@ namespace snmalloc
SNMALLOC_FAST_PATH CapPtr<T, bounds>
load(std::memory_order order = std::memory_order_seq_cst) noexcept
{
return CapPtr<T, bounds>(this->unsafe_capptr.load(order));
return CapPtr<T, bounds>::unsafe_from(this->unsafe_capptr.load(order));
}
SNMALLOC_FAST_PATH void store(
@@ -504,7 +518,7 @@ namespace snmalloc
CapPtr<T, bounds> desired,
std::memory_order order = std::memory_order_seq_cst) noexcept
{
return CapPtr<T, bounds>(
return CapPtr<T, bounds>::unsafe_from(
this->unsafe_capptr.exchange(desired.unsafe_ptr(), order));
}

View File

@@ -102,8 +102,8 @@ namespace snmalloc
UNUSED(ls);
return CapPtr<
T,
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>(
p.unsafe_ptr());
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>::
unsafe_from(p.unsafe_ptr());
}
}
} // namespace snmalloc

View File

@@ -506,10 +506,10 @@ namespace snmalloc
* The front of the queue has already been validated; just change the
* annotating type.
*/
auto domesticate_first = [](freelist::QueuePtr p)
SNMALLOC_FAST_PATH_LAMBDA {
return freelist::HeadPtr(p.unsafe_ptr());
};
auto domesticate_first =
[](freelist::QueuePtr p) SNMALLOC_FAST_PATH_LAMBDA {
return freelist::HeadPtr::unsafe_from(p.unsafe_ptr());
};
message_queue().dequeue(key_global, domesticate_first, domesticate, cb);
}
else

View File

@@ -270,7 +270,8 @@ namespace snmalloc
inline static BQueuePtr<BQueue> encode_next(
address_t curr, BHeadPtr<BView, BQueue> next, const FreeListKey& key)
{
return BQueuePtr<BQueue>(code_next(curr, next.unsafe_ptr(), key));
return BQueuePtr<BQueue>::unsafe_from(
code_next(curr, next.unsafe_ptr(), key));
}
/**
@@ -294,7 +295,8 @@ namespace snmalloc
inline static BHeadPtr<BView, BQueue> decode_next(
address_t curr, BHeadPtr<BView, BQueue> next, const FreeListKey& key)
{
return BHeadPtr<BView, BQueue>(code_next(curr, next.unsafe_ptr(), key));
return BHeadPtr<BView, BQueue>::unsafe_from(
code_next(curr, next.unsafe_ptr(), key));
}
template<
@@ -543,7 +545,7 @@ namespace snmalloc
Object::BHeadPtr<BView, BQueue> cast_head(uint32_t ix)
{
return Object::BHeadPtr<BView, BQueue>(
return Object::BHeadPtr<BView, BQueue>::unsafe_from(
static_cast<Object::T<BQueue>*>(head[ix]));
}
@@ -715,8 +717,8 @@ namespace snmalloc
// this is doing a CONTAINING_RECORD like cast to get back
// to the actual object. This isn't true if the builder is
// empty, but you are not allowed to call this in the empty case.
auto last =
Object::BHeadPtr<BView, BQueue>(Object::from_next_ptr(cast_end(0)));
auto last = Object::BHeadPtr<BView, BQueue>::unsafe_from(
Object::from_next_ptr(cast_end(0)));
init();
return {first, last};
}

View File

@@ -115,7 +115,7 @@ namespace snmalloc
if constexpr (Config::Options.QueueHeadsAreTame)
{
auto domesticate_nop = [](freelist::QueuePtr p) {
return freelist::HeadPtr(p.unsafe_ptr());
return freelist::HeadPtr::unsafe_from(p.unsafe_ptr());
};
remote->enqueue(first, last, key, domesticate_nop);
}

View File

@@ -90,7 +90,8 @@ namespace snmalloc
CapPtr<T, capptr::user_address_control_type<B>>>
capptr_to_user_address_control(CapPtr<T, B> p)
{
return CapPtr<T, capptr::user_address_control_type<B>>(p.unsafe_ptr());
return CapPtr<T, capptr::user_address_control_type<B>>::unsafe_from(
p.unsafe_ptr());
}
template<

View File

@@ -135,7 +135,7 @@ namespace snmalloc
return nullptr;
}
}
return CapPtr<T, capptr::user_address_control_type<B>>(
return CapPtr<T, capptr::user_address_control_type<B>>::unsafe_from(
__builtin_cheri_perms_and(
p.unsafe_ptr(), ~static_cast<unsigned int>(CHERI_PERM_SW_VMEM)));
}

View File

@@ -108,8 +108,8 @@ namespace snmalloc
return CapPtr<
T,
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>(
p.unsafe_ptr());
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>::
unsafe_from(p.unsafe_ptr());
}
};