NFC: Introduce pointer domestication backend support
`capptr_domesticate<Backend>(Backend::LocalState*, CapPtr<T, B>)` is the intended affordance for conversion to covert from a `CapPtr<T, B>` with `B::wildness` `Wild` to a `CapPtr<>` with `B::with_wildness<Tame>` and thence plumbed into the rest of the machinery. David added the SFINAE wrapper so that `Backend`-s now don't need to implement a domestication callback; instead, if the `Backend` does not provide a `capptr_domesticate` function, a default, which just does an explicit type cast, will be used instead. This is not yet hooked into the rest of the tree. Co-authored-by: David Chisnall <David.Chisnall@microsoft.com>
This commit is contained in:
committed by
Nathaniel Wesley Filardo
parent
7e53a2e82a
commit
1a608e6066
@@ -294,6 +294,23 @@ namespace snmalloc
|
||||
UNUSED(ls);
|
||||
concretePagemap.register_range(p, sz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bounds of the memory this back-end manages as a pair of
|
||||
* addresses (start then end). This is available iff this is a
|
||||
* fixed-range Backend.
|
||||
*/
|
||||
template<bool fixed_range_ = fixed_range>
|
||||
static SNMALLOC_FAST_PATH
|
||||
std::enable_if_t<fixed_range_, std::pair<address_t, address_t>>
|
||||
get_bounds(LocalState* local_state)
|
||||
{
|
||||
static_assert(
|
||||
fixed_range_ == fixed_range, "Don't set SFINAE parameter!");
|
||||
|
||||
UNUSED(local_state);
|
||||
return concretePagemap.get_bounds();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -58,6 +58,24 @@ namespace snmalloc
|
||||
concept ConceptBackendMetaRange =
|
||||
ConceptBackendMeta<Meta> && ConceptBackendMeta_Range<Meta>;
|
||||
|
||||
/**
|
||||
* The backend also defines domestication (that is, the difference between
|
||||
* Tame and Wild CapPtr bounds). It exports the intended affordance for
|
||||
* testing a Wild pointer and either returning nullptr or the original
|
||||
* pointer, now Tame.
|
||||
*/
|
||||
template<typename Globals>
|
||||
concept ConceptBackendDomestication =
|
||||
requires(typename Globals::LocalState* ls,
|
||||
capptr::AllocWild<void> ptr)
|
||||
{
|
||||
{ Globals::capptr_domesticate(ls, ptr) }
|
||||
-> ConceptSame<capptr::Alloc<void>>;
|
||||
|
||||
{ Globals::capptr_domesticate(ls, ptr.template as_static<char>()) }
|
||||
-> ConceptSame<capptr::Alloc<char>>;
|
||||
};
|
||||
|
||||
class CommonConfig;
|
||||
struct Flags;
|
||||
|
||||
@@ -89,6 +107,7 @@ namespace snmalloc
|
||||
|
||||
typename Globals::GlobalPoolState;
|
||||
{ Globals::pool() } -> ConceptSame<typename Globals::GlobalPoolState &>;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/defines.h"
|
||||
#include "../mem/remotecache.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -137,4 +136,54 @@ namespace snmalloc
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* SFINAE helper, calls capptr_domesticate in the backend if it exists.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendDomestication) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState* ls, CapPtr<T, B> p, int)
|
||||
-> decltype(Backend::capptr_domesticate(ls, p))
|
||||
{
|
||||
return Backend::capptr_domesticate(ls, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. If the back end does not provide special handling for
|
||||
* domestication then assume all wild pointers can be domesticated.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendGlobals) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState*, CapPtr<T, B> p, long)
|
||||
{
|
||||
return CapPtr<
|
||||
T,
|
||||
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>(
|
||||
p.unsafe_ptr());
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Wrapper that calls `Backend::capptr_domesticate` if and only if it is
|
||||
* implemented. If it is not implemented then this assumes that any wild
|
||||
* pointer can be domesticated.
|
||||
*/
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptBackendGlobals) Backend,
|
||||
typename T,
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
SNMALLOC_FAST_PATH_INLINE auto
|
||||
capptr_domesticate(typename Backend::LocalState* ls, CapPtr<T, B> p)
|
||||
{
|
||||
return detail::capptr_domesticate<Backend>(ls, p, 0);
|
||||
}
|
||||
|
||||
} // namespace snmalloc
|
||||
#include "../mem/remotecache.h"
|
||||
|
||||
@@ -51,5 +51,33 @@ namespace snmalloc
|
||||
{
|
||||
Backend::init(local_state, base, length);
|
||||
}
|
||||
|
||||
/* Verify that a pointer points into the region managed by this config */
|
||||
template<typename T, SNMALLOC_CONCEPT(capptr::ConceptBound) B>
|
||||
static SNMALLOC_FAST_PATH CapPtr<
|
||||
T,
|
||||
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>
|
||||
capptr_domesticate(typename Backend::LocalState* ls, CapPtr<T, B> p)
|
||||
{
|
||||
static_assert(B::wildness == capptr::dimension::Wildness::Wild);
|
||||
|
||||
static const size_t sz = sizeof(
|
||||
std::conditional<std::is_same_v<std::remove_cv<T>, void>, void*, T>);
|
||||
|
||||
UNUSED(ls);
|
||||
auto address = address_cast(p);
|
||||
auto bounds = Backend::Pagemap::get_bounds(nullptr);
|
||||
if (
|
||||
(address < bounds.first) || (address > bounds.second) ||
|
||||
((bounds.second - address) < sz))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CapPtr<
|
||||
T,
|
||||
typename B::template with_wildness<capptr::dimension::Wildness::Tame>>(
|
||||
p.unsafe_ptr());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -205,6 +205,15 @@ namespace snmalloc
|
||||
body_opt = new_body;
|
||||
}
|
||||
|
||||
template<bool has_bounds_ = has_bounds>
|
||||
std::enable_if_t<has_bounds_, std::pair<address_t, size_t>> get_bounds()
|
||||
{
|
||||
static_assert(
|
||||
has_bounds_ == has_bounds, "Don't set SFINAE template parameter!");
|
||||
|
||||
return {base, size};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of entries.
|
||||
*/
|
||||
|
||||
@@ -569,6 +569,11 @@ namespace snmalloc
|
||||
#ifdef SNMALLOC_PASS_THROUGH
|
||||
return external_alloc::malloc_usable_size(const_cast<void*>(p_raw));
|
||||
#else
|
||||
// TODO What's the domestication policy here? At the moment we just probe
|
||||
// the pagemap with the raw address, without checks. There could be
|
||||
// implicit domestication through the `SharedStateHandle::Pagemap` or we
|
||||
// could just leave well enough alone.
|
||||
|
||||
// Note that this should return 0 for nullptr.
|
||||
// Other than nullptr, we know the system will be initialised as it must
|
||||
// be called with something we have already allocated.
|
||||
@@ -600,6 +605,11 @@ namespace snmalloc
|
||||
void* external_pointer(void* p_raw)
|
||||
{
|
||||
#ifndef SNMALLOC_PASS_THROUGH
|
||||
// TODO What's the domestication policy here? At the moment we just probe
|
||||
// the pagemap with the raw address, without checks. There could be
|
||||
// implicit domestication through the `SharedStateHandle::Pagemap` or we
|
||||
// could just leave well enough alone.
|
||||
|
||||
// TODO bring back the CHERI bits. Wes to review if required.
|
||||
MetaEntry entry =
|
||||
SharedStateHandle::Pagemap::template get_metaentry<true>(
|
||||
|
||||
Reference in New Issue
Block a user