mem/metaslab: use uintptr_t alignment functions

It is UB to offset from `nullptr` (except perhaps with a 0 offset).  Apparently
clang is able to use this to reason, given `void* p`, that comparing
`__builtin_align_down(p, x)` against `handle.fake_large_remote` (i.e., a `static
inline constexpr` `nullptr`) must be the same as comparing `p` itself against
`nullptr`.

In `MetaEntry`'s constructor, converting the provided `RemoteAllocator*` to
`uintptr_t` before offsetting avoids the UB.  (While here, don't use
`address_cast()`, as `address_t` will, on CHERI, be `ptraddr_t` and not
`uintptr_t`.)

Doing the alignment in `get_remote` at `uintptr_t` before casting to
`RemoteAllocator*`, rather than converting and then aligning, prevents the
reasoning above from eliminating the alignment.
This commit is contained in:
Nathaniel Wesley Filardo
2021-07-20 12:13:56 +01:00
committed by Matthew Parkinson
parent 3e70963772
commit 2ba0de76b3

View File

@@ -180,8 +180,9 @@ namespace snmalloc
MetaEntry(Metaslab* meta, RemoteAllocator* remote, sizeclass_t sizeclass)
: meta(meta)
{
/* remote might be nullptr; cast to uintptr_t before offsetting */
remote_and_sizeclass =
address_cast(pointer_offset<char>(remote, sizeclass));
pointer_offset(reinterpret_cast<uintptr_t>(remote), sizeclass);
}
[[nodiscard]] Metaslab* get_metaslab() const
@@ -192,7 +193,7 @@ namespace snmalloc
[[nodiscard]] RemoteAllocator* get_remote() const
{
return reinterpret_cast<RemoteAllocator*>(
bits::align_down(remote_and_sizeclass, alignof(RemoteAllocator)));
pointer_align_down<alignof(RemoteAllocator)>(remote_and_sizeclass));
}
[[nodiscard]] sizeclass_t get_sizeclass() const