FreeObject: hide harder from the compiler, tweak types

On CHERI, the compiler will always issue a warning for
`reinterpret_cast<T*>(ptraddr_t)` and similar expressions, and of course, if the
compiler can see far enough into the types, the presence of `if constexpr` will
not save us.  Therefore, lift the conditional out to two definitions of
`FreeObject::encode` using `std::enable_if_t` to gate which is used.
This commit is contained in:
Nathaniel Filardo
2021-03-23 18:49:50 +00:00
committed by Matthew Parkinson
parent afc6283e01
commit c5b65d07b8

View File

@@ -68,29 +68,45 @@ namespace snmalloc
{
FreeObject* reference;
public:
static inline FreeObject*
encode(uint16_t local_key, FreeObject* next_object)
{
#ifdef CHECK_CLIENT
if constexpr (aal_supports<IntegerPointers>)
{
// Simple involutional encoding. The bottom half of each word is
// multiplied by a function of both global and local keys (the latter,
// in practice, being the address of the previous list entry) and the
// resulting word's top part is XORed into the pointer value before it
// is stored.
auto next = address_cast(next_object);
constexpr address_t MASK = bits::one_at_bit(PRESERVE_BOTTOM_BITS) - 1;
// Mix in local_key
address_t key = (local_key + 1) * global_key;
next ^= (((next & MASK) + 1) * key) &
~(bits::one_at_bit(PRESERVE_BOTTOM_BITS) - 1);
next_object = reinterpret_cast<FreeObject*>(next);
}
/**
* On architectures which use IntegerPointers, we can obfuscate our free
* lists and use this to drive some probabilistic checks for integrity.
*
* There are two definitions of encode() below, which use std::enable_if_t
* to gate on do_encode.
*/
#ifndef CHECK_CLIENT
static constexpr bool do_encode = false;
#else
UNUSED(local_key);
static constexpr bool do_encode = aal_supports<IntegerPointers, Aal>;
#endif
public:
#ifdef CHECK_CLIENT
template<typename T = FreeObject>
static std::enable_if_t<do_encode, T*>
encode(uint16_t local_key, T* next_object)
{
// Simple involutional encoding. The bottom half of each word is
// multiplied by a function of both global and local keys (the latter,
// in practice, being the address of the previous list entry) and the
// resulting word's top part is XORed into the pointer value before it
// is stored.
auto next = address_cast(next_object);
constexpr address_t MASK = bits::one_at_bit(PRESERVE_BOTTOM_BITS) - 1;
// Mix in local_key
address_t key = (local_key + 1) * global_key;
next ^= (((next & MASK) + 1) * key) &
~(bits::one_at_bit(PRESERVE_BOTTOM_BITS) - 1);
return reinterpret_cast<FreeObject*>(next);
}
#endif
template<typename T = FreeObject>
static std::enable_if_t<!do_encode, T*>
encode(uint16_t local_key, T* next_object)
{
UNUSED(local_key);
return next_object;
}