Skip to content

Commit 26324e8

Browse files
nwf-msrnwf
authored andcommitted
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.
1 parent 4ad99d7 commit 26324e8

6 files changed

Lines changed: 45 additions & 21 deletions

File tree

src/ds/address.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ namespace snmalloc
2828
inline U* pointer_offset(T* base, size_t diff)
2929
{
3030
SNMALLOC_ASSERT(base != nullptr); /* Avoid UB */
31-
return reinterpret_cast<U*>(
32-
reinterpret_cast<uintptr_t>(base) + static_cast<uintptr_t>(diff));
31+
return unsafe_from_uintptr<U>(
32+
unsafe_to_uintptr<T>(base) + static_cast<uintptr_t>(diff));
3333
}
3434

3535
template<SNMALLOC_CONCEPT(capptr::ConceptBound) bounds, typename T>
@@ -129,8 +129,8 @@ namespace snmalloc
129129
template<size_t alignment, typename T = void>
130130
inline T* pointer_align_down(void* p)
131131
{
132-
return reinterpret_cast<T*>(
133-
pointer_align_down<alignment>(reinterpret_cast<uintptr_t>(p)));
132+
return unsafe_from_uintptr<T>(
133+
pointer_align_down<alignment>(unsafe_to_uintptr<void>(p)));
134134
}
135135

136136
template<
@@ -164,8 +164,8 @@ namespace snmalloc
164164
#if __has_builtin(__builtin_align_up)
165165
return static_cast<T*>(__builtin_align_up(p, alignment));
166166
#else
167-
return reinterpret_cast<T*>(
168-
bits::align_up(reinterpret_cast<uintptr_t>(p), alignment));
167+
return unsafe_from_uintptr<T>(
168+
bits::align_up(unsafe_to_uintptr<void>(p), alignment));
169169
#endif
170170
}
171171
}
@@ -197,8 +197,8 @@ namespace snmalloc
197197
#if __has_builtin(__builtin_align_down)
198198
return static_cast<T*>(__builtin_align_down(p, alignment));
199199
#else
200-
return reinterpret_cast<T*>(
201-
bits::align_down(reinterpret_cast<uintptr_t>(p), alignment));
200+
return unsafe_from_uintptr<T>(
201+
bits::align_down(unsafe_to_uintptr<void>(p), alignment));
202202
#endif
203203
}
204204

@@ -221,8 +221,8 @@ namespace snmalloc
221221
#if __has_builtin(__builtin_align_up)
222222
return static_cast<T*>(__builtin_align_up(p, alignment));
223223
#else
224-
return reinterpret_cast<T*>(
225-
bits::align_up(reinterpret_cast<uintptr_t>(p), alignment));
224+
return unsafe_from_uintptr<T>(
225+
bits::align_up(unsafe_to_uintptr<void>(p), alignment));
226226
#endif
227227
}
228228

src/ds/ptrwrap.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,30 @@
77

88
namespace snmalloc
99
{
10+
/*
11+
* reinterpret_cast<> is a powerful primitive that, excitingly, does not
12+
* require the programmer to annotate the expected *source* type. We
13+
* therefore wrap its use to interconvert between uintptr_t and pointer types.
14+
*/
15+
16+
/**
17+
* Convert a pointer to a uintptr_t. Template argument inference is
18+
* prohibited.
19+
*/
20+
template<typename T>
21+
SNMALLOC_FAST_PATH_INLINE uintptr_t
22+
unsafe_to_uintptr(std::enable_if_t<true, T>* p)
23+
{
24+
return reinterpret_cast<uintptr_t>(p);
25+
}
26+
27+
/** Convert a uintptr_t to a T*. */
28+
template<typename T>
29+
SNMALLOC_FAST_PATH_INLINE T* unsafe_from_uintptr(uintptr_t p)
30+
{
31+
return reinterpret_cast<T*>(p);
32+
}
33+
1034
/**
1135
* To assist in providing a uniform interface regardless of pointer wrapper,
1236
* we also export intrinsic pointer and atomic pointer aliases, as the postfix
@@ -321,7 +345,7 @@ namespace snmalloc
321345

322346
[[nodiscard]] SNMALLOC_FAST_PATH uintptr_t unsafe_uintptr() const
323347
{
324-
return reinterpret_cast<uintptr_t>(this->unsafe_capptr);
348+
return unsafe_to_uintptr<T>(this->unsafe_capptr);
325349
}
326350
};
327351

src/mem/freelist.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ namespace snmalloc
239239

240240
if constexpr (CHECK_CLIENT && !aal_supports<StrictProvenance>)
241241
{
242-
return reinterpret_cast<Object::T<BQueue>*>(
243-
reinterpret_cast<uintptr_t>(next) ^ key.key_next);
242+
return unsafe_from_uintptr<Object::T<BQueue>>(
243+
unsafe_to_uintptr<Object::T<BQueue>>(next) ^ key.key_next);
244244
}
245245
else
246246
{

src/mem/metaslab.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ namespace snmalloc
272272
*/
273273
SNMALLOC_FAST_PATH
274274
MetaEntry(Metaslab* meta, uintptr_t remote_and_sizeclass)
275-
: meta(reinterpret_cast<uintptr_t>(meta)),
275+
: meta(unsafe_to_uintptr<Metaslab>(meta)),
276276
remote_and_sizeclass(remote_and_sizeclass)
277277
{}
278278

@@ -281,11 +281,11 @@ namespace snmalloc
281281
Metaslab* meta,
282282
RemoteAllocator* remote,
283283
sizeclass_t sizeclass = sizeclass_t())
284-
: meta(reinterpret_cast<uintptr_t>(meta))
284+
: meta(unsafe_to_uintptr<Metaslab>(meta))
285285
{
286286
/* remote might be nullptr; cast to uintptr_t before offsetting */
287-
remote_and_sizeclass =
288-
pointer_offset(reinterpret_cast<uintptr_t>(remote), sizeclass.raw());
287+
remote_and_sizeclass = pointer_offset(
288+
unsafe_to_uintptr<RemoteAllocator>(remote), sizeclass.raw());
289289
}
290290

291291
/**
@@ -296,7 +296,7 @@ namespace snmalloc
296296
[[nodiscard]] SNMALLOC_FAST_PATH Metaslab* get_metaslab() const
297297
{
298298
SNMALLOC_ASSERT(get_remote() != nullptr);
299-
return reinterpret_cast<Metaslab*>(meta & ~BOUNDARY_BIT);
299+
return unsafe_from_uintptr<Metaslab>(meta & ~BOUNDARY_BIT);
300300
}
301301

302302
/**
@@ -312,7 +312,7 @@ namespace snmalloc
312312

313313
[[nodiscard]] SNMALLOC_FAST_PATH RemoteAllocator* get_remote() const
314314
{
315-
return reinterpret_cast<RemoteAllocator*>(
315+
return unsafe_from_uintptr<RemoteAllocator>(
316316
pointer_align_down<REMOTE_WITH_BACKEND_MARKER_ALIGN>(
317317
remote_and_sizeclass));
318318
}

src/test/func/external_pagemap/external_pagemap.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ int main()
2020
auto& global = GlobalChunkmap::pagemap();
2121
SNMALLOC_CHECK(&p == &global);
2222
// Get a valid heap address
23-
uintptr_t addr = reinterpret_cast<uintptr_t>(malloc(42));
23+
uintptr_t addr = unsafe_to_uintptr<void>(malloc(42));
2424
// Make this very strongly aligned
2525
addr &= ~0xfffffULL;
2626
void* page = p.page_for_address(addr);

src/test/func/malloc/malloc.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ int main(int argc, char** argv)
212212
//
213213
// Note: We cannot use the check or assert macros here because they depend on
214214
// `MessageBuilder` working. They are safe to use in any other test.
215-
void* fakeptr = reinterpret_cast<void*>(static_cast<uintptr_t>(0x42));
215+
void* fakeptr = unsafe_from_uintptr<void>(static_cast<uintptr_t>(0x42));
216216
MessageBuilder<1024> b{
217217
"testing pointer {} size_t {} message, {} world, null is {}, -123456 is "
218218
"{}, 1234567 is {}",

0 commit comments

Comments
 (0)