Add and plumb unsafe_{to,from}_uintptr<T> casts
These encapsulate the wildly powerful reinterpret_cast<> operator where one side is a uintptr_t and the other is a native pointer. In both cases we require the pointer type to be explicitly given.
This commit is contained in:
committed by
Nathaniel Wesley Filardo
parent
4ad99d7392
commit
26324e8bfc
@@ -28,8 +28,8 @@ namespace snmalloc
|
||||
inline U* pointer_offset(T* base, size_t diff)
|
||||
{
|
||||
SNMALLOC_ASSERT(base != nullptr); /* Avoid UB */
|
||||
return reinterpret_cast<U*>(
|
||||
reinterpret_cast<uintptr_t>(base) + static_cast<uintptr_t>(diff));
|
||||
return unsafe_from_uintptr<U>(
|
||||
unsafe_to_uintptr<T>(base) + static_cast<uintptr_t>(diff));
|
||||
}
|
||||
|
||||
template<SNMALLOC_CONCEPT(capptr::ConceptBound) bounds, typename T>
|
||||
@@ -129,8 +129,8 @@ namespace snmalloc
|
||||
template<size_t alignment, typename T = void>
|
||||
inline T* pointer_align_down(void* p)
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
pointer_align_down<alignment>(reinterpret_cast<uintptr_t>(p)));
|
||||
return unsafe_from_uintptr<T>(
|
||||
pointer_align_down<alignment>(unsafe_to_uintptr<void>(p)));
|
||||
}
|
||||
|
||||
template<
|
||||
@@ -164,8 +164,8 @@ namespace snmalloc
|
||||
#if __has_builtin(__builtin_align_up)
|
||||
return static_cast<T*>(__builtin_align_up(p, alignment));
|
||||
#else
|
||||
return reinterpret_cast<T*>(
|
||||
bits::align_up(reinterpret_cast<uintptr_t>(p), alignment));
|
||||
return unsafe_from_uintptr<T>(
|
||||
bits::align_up(unsafe_to_uintptr<void>(p), alignment));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -197,8 +197,8 @@ namespace snmalloc
|
||||
#if __has_builtin(__builtin_align_down)
|
||||
return static_cast<T*>(__builtin_align_down(p, alignment));
|
||||
#else
|
||||
return reinterpret_cast<T*>(
|
||||
bits::align_down(reinterpret_cast<uintptr_t>(p), alignment));
|
||||
return unsafe_from_uintptr<T>(
|
||||
bits::align_down(unsafe_to_uintptr<void>(p), alignment));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -221,8 +221,8 @@ namespace snmalloc
|
||||
#if __has_builtin(__builtin_align_up)
|
||||
return static_cast<T*>(__builtin_align_up(p, alignment));
|
||||
#else
|
||||
return reinterpret_cast<T*>(
|
||||
bits::align_up(reinterpret_cast<uintptr_t>(p), alignment));
|
||||
return unsafe_from_uintptr<T>(
|
||||
bits::align_up(unsafe_to_uintptr<void>(p), alignment));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,30 @@
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/*
|
||||
* reinterpret_cast<> is a powerful primitive that, excitingly, does not
|
||||
* require the programmer to annotate the expected *source* type. We
|
||||
* therefore wrap its use to interconvert between uintptr_t and pointer types.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a pointer to a uintptr_t. Template argument inference is
|
||||
* prohibited.
|
||||
*/
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH_INLINE uintptr_t
|
||||
unsafe_to_uintptr(std::enable_if_t<true, T>* p)
|
||||
{
|
||||
return reinterpret_cast<uintptr_t>(p);
|
||||
}
|
||||
|
||||
/** Convert a uintptr_t to a T*. */
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH_INLINE T* unsafe_from_uintptr(uintptr_t p)
|
||||
{
|
||||
return reinterpret_cast<T*>(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* To assist in providing a uniform interface regardless of pointer wrapper,
|
||||
* we also export intrinsic pointer and atomic pointer aliases, as the postfix
|
||||
@@ -321,7 +345,7 @@ namespace snmalloc
|
||||
|
||||
[[nodiscard]] SNMALLOC_FAST_PATH uintptr_t unsafe_uintptr() const
|
||||
{
|
||||
return reinterpret_cast<uintptr_t>(this->unsafe_capptr);
|
||||
return unsafe_to_uintptr<T>(this->unsafe_capptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -239,8 +239,8 @@ namespace snmalloc
|
||||
|
||||
if constexpr (CHECK_CLIENT && !aal_supports<StrictProvenance>)
|
||||
{
|
||||
return reinterpret_cast<Object::T<BQueue>*>(
|
||||
reinterpret_cast<uintptr_t>(next) ^ key.key_next);
|
||||
return unsafe_from_uintptr<Object::T<BQueue>>(
|
||||
unsafe_to_uintptr<Object::T<BQueue>>(next) ^ key.key_next);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -272,7 +272,7 @@ namespace snmalloc
|
||||
*/
|
||||
SNMALLOC_FAST_PATH
|
||||
MetaEntry(Metaslab* meta, uintptr_t remote_and_sizeclass)
|
||||
: meta(reinterpret_cast<uintptr_t>(meta)),
|
||||
: meta(unsafe_to_uintptr<Metaslab>(meta)),
|
||||
remote_and_sizeclass(remote_and_sizeclass)
|
||||
{}
|
||||
|
||||
@@ -281,11 +281,11 @@ namespace snmalloc
|
||||
Metaslab* meta,
|
||||
RemoteAllocator* remote,
|
||||
sizeclass_t sizeclass = sizeclass_t())
|
||||
: meta(reinterpret_cast<uintptr_t>(meta))
|
||||
: meta(unsafe_to_uintptr<Metaslab>(meta))
|
||||
{
|
||||
/* remote might be nullptr; cast to uintptr_t before offsetting */
|
||||
remote_and_sizeclass =
|
||||
pointer_offset(reinterpret_cast<uintptr_t>(remote), sizeclass.raw());
|
||||
remote_and_sizeclass = pointer_offset(
|
||||
unsafe_to_uintptr<RemoteAllocator>(remote), sizeclass.raw());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,7 +296,7 @@ namespace snmalloc
|
||||
[[nodiscard]] SNMALLOC_FAST_PATH Metaslab* get_metaslab() const
|
||||
{
|
||||
SNMALLOC_ASSERT(get_remote() != nullptr);
|
||||
return reinterpret_cast<Metaslab*>(meta & ~BOUNDARY_BIT);
|
||||
return unsafe_from_uintptr<Metaslab>(meta & ~BOUNDARY_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,7 +312,7 @@ namespace snmalloc
|
||||
|
||||
[[nodiscard]] SNMALLOC_FAST_PATH RemoteAllocator* get_remote() const
|
||||
{
|
||||
return reinterpret_cast<RemoteAllocator*>(
|
||||
return unsafe_from_uintptr<RemoteAllocator>(
|
||||
pointer_align_down<REMOTE_WITH_BACKEND_MARKER_ALIGN>(
|
||||
remote_and_sizeclass));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ int main()
|
||||
auto& global = GlobalChunkmap::pagemap();
|
||||
SNMALLOC_CHECK(&p == &global);
|
||||
// Get a valid heap address
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(malloc(42));
|
||||
uintptr_t addr = unsafe_to_uintptr<void>(malloc(42));
|
||||
// Make this very strongly aligned
|
||||
addr &= ~0xfffffULL;
|
||||
void* page = p.page_for_address(addr);
|
||||
|
||||
@@ -212,7 +212,7 @@ int main(int argc, char** argv)
|
||||
//
|
||||
// Note: We cannot use the check or assert macros here because they depend on
|
||||
// `MessageBuilder` working. They are safe to use in any other test.
|
||||
void* fakeptr = reinterpret_cast<void*>(static_cast<uintptr_t>(0x42));
|
||||
void* fakeptr = unsafe_from_uintptr<void>(static_cast<uintptr_t>(0x42));
|
||||
MessageBuilder<1024> b{
|
||||
"testing pointer {} size_t {} message, {} world, null is {}, -123456 is "
|
||||
"{}, 1234567 is {}",
|
||||
|
||||
Reference in New Issue
Block a user