diff --git a/src/ds/address.h b/src/ds/address.h index 0c3cdc7..a6a161a 100644 --- a/src/ds/address.h +++ b/src/ds/address.h @@ -28,8 +28,8 @@ namespace snmalloc inline U* pointer_offset(T* base, size_t diff) { SNMALLOC_ASSERT(base != nullptr); /* Avoid UB */ - return reinterpret_cast( - reinterpret_cast(base) + static_cast(diff)); + return unsafe_from_uintptr( + unsafe_to_uintptr(base) + static_cast(diff)); } template @@ -129,8 +129,8 @@ namespace snmalloc template inline T* pointer_align_down(void* p) { - return reinterpret_cast( - pointer_align_down(reinterpret_cast(p))); + return unsafe_from_uintptr( + pointer_align_down(unsafe_to_uintptr(p))); } template< @@ -164,8 +164,8 @@ namespace snmalloc #if __has_builtin(__builtin_align_up) return static_cast(__builtin_align_up(p, alignment)); #else - return reinterpret_cast( - bits::align_up(reinterpret_cast(p), alignment)); + return unsafe_from_uintptr( + bits::align_up(unsafe_to_uintptr(p), alignment)); #endif } } @@ -197,8 +197,8 @@ namespace snmalloc #if __has_builtin(__builtin_align_down) return static_cast(__builtin_align_down(p, alignment)); #else - return reinterpret_cast( - bits::align_down(reinterpret_cast(p), alignment)); + return unsafe_from_uintptr( + bits::align_down(unsafe_to_uintptr(p), alignment)); #endif } @@ -221,8 +221,8 @@ namespace snmalloc #if __has_builtin(__builtin_align_up) return static_cast(__builtin_align_up(p, alignment)); #else - return reinterpret_cast( - bits::align_up(reinterpret_cast(p), alignment)); + return unsafe_from_uintptr( + bits::align_up(unsafe_to_uintptr(p), alignment)); #endif } diff --git a/src/ds/ptrwrap.h b/src/ds/ptrwrap.h index 8b91a01..b94c90f 100644 --- a/src/ds/ptrwrap.h +++ b/src/ds/ptrwrap.h @@ -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 + SNMALLOC_FAST_PATH_INLINE uintptr_t + unsafe_to_uintptr(std::enable_if_t* p) + { + return reinterpret_cast(p); + } + + /** Convert a uintptr_t to a T*. */ + template + SNMALLOC_FAST_PATH_INLINE T* unsafe_from_uintptr(uintptr_t p) + { + return reinterpret_cast(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(this->unsafe_capptr); + return unsafe_to_uintptr(this->unsafe_capptr); } }; diff --git a/src/mem/freelist.h b/src/mem/freelist.h index bac781c..9850b61 100644 --- a/src/mem/freelist.h +++ b/src/mem/freelist.h @@ -239,8 +239,8 @@ namespace snmalloc if constexpr (CHECK_CLIENT && !aal_supports) { - return reinterpret_cast*>( - reinterpret_cast(next) ^ key.key_next); + return unsafe_from_uintptr>( + unsafe_to_uintptr>(next) ^ key.key_next); } else { diff --git a/src/mem/metaslab.h b/src/mem/metaslab.h index a046e09..947b22d 100644 --- a/src/mem/metaslab.h +++ b/src/mem/metaslab.h @@ -272,7 +272,7 @@ namespace snmalloc */ SNMALLOC_FAST_PATH MetaEntry(Metaslab* meta, uintptr_t remote_and_sizeclass) - : meta(reinterpret_cast(meta)), + : meta(unsafe_to_uintptr(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(meta)) + : meta(unsafe_to_uintptr(meta)) { /* remote might be nullptr; cast to uintptr_t before offsetting */ - remote_and_sizeclass = - pointer_offset(reinterpret_cast(remote), sizeclass.raw()); + remote_and_sizeclass = pointer_offset( + unsafe_to_uintptr(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(meta & ~BOUNDARY_BIT); + return unsafe_from_uintptr(meta & ~BOUNDARY_BIT); } /** @@ -312,7 +312,7 @@ namespace snmalloc [[nodiscard]] SNMALLOC_FAST_PATH RemoteAllocator* get_remote() const { - return reinterpret_cast( + return unsafe_from_uintptr( pointer_align_down( remote_and_sizeclass)); } diff --git a/src/test/func/external_pagemap/external_pagemap.cc b/src/test/func/external_pagemap/external_pagemap.cc index 6fee03f..3d139a4 100644 --- a/src/test/func/external_pagemap/external_pagemap.cc +++ b/src/test/func/external_pagemap/external_pagemap.cc @@ -20,7 +20,7 @@ int main() auto& global = GlobalChunkmap::pagemap(); SNMALLOC_CHECK(&p == &global); // Get a valid heap address - uintptr_t addr = reinterpret_cast(malloc(42)); + uintptr_t addr = unsafe_to_uintptr(malloc(42)); // Make this very strongly aligned addr &= ~0xfffffULL; void* page = p.page_for_address(addr); diff --git a/src/test/func/malloc/malloc.cc b/src/test/func/malloc/malloc.cc index b5bd9ff..4d7ae28 100644 --- a/src/test/func/malloc/malloc.cc +++ b/src/test/func/malloc/malloc.cc @@ -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(static_cast(0x42)); + void* fakeptr = unsafe_from_uintptr(static_cast(0x42)); MessageBuilder<1024> b{ "testing pointer {} size_t {} message, {} world, null is {}, -123456 is " "{}, 1234567 is {}",