diff --git a/src/backend/backend.h b/src/backend/backend.h index daf0363..36328f4 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -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 + static SNMALLOC_FAST_PATH + std::enable_if_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: diff --git a/src/backend/backend_concept.h b/src/backend/backend_concept.h index 96c7319..e4cbc91 100644 --- a/src/backend/backend_concept.h +++ b/src/backend/backend_concept.h @@ -58,6 +58,24 @@ namespace snmalloc concept ConceptBackendMetaRange = ConceptBackendMeta && ConceptBackendMeta_Range; + /** + * 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 + concept ConceptBackendDomestication = + requires(typename Globals::LocalState* ls, + capptr::AllocWild ptr) + { + { Globals::capptr_domesticate(ls, ptr) } + -> ConceptSame>; + + { Globals::capptr_domesticate(ls, ptr.template as_static()) } + -> ConceptSame>; + }; + class CommonConfig; struct Flags; @@ -89,6 +107,7 @@ namespace snmalloc typename Globals::GlobalPoolState; { Globals::pool() } -> ConceptSame; + }; /** diff --git a/src/backend/commonconfig.h b/src/backend/commonconfig.h index 2e11879..abc3333 100644 --- a/src/backend/commonconfig.h +++ b/src/backend/commonconfig.h @@ -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 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 p, long) + { + return CapPtr< + T, + typename B::template with_wildness>( + 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 p) + { + return detail::capptr_domesticate(ls, p, 0); + } + } // namespace snmalloc +#include "../mem/remotecache.h" diff --git a/src/backend/fixedglobalconfig.h b/src/backend/fixedglobalconfig.h index 7864723..761c371 100644 --- a/src/backend/fixedglobalconfig.h +++ b/src/backend/fixedglobalconfig.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 + static SNMALLOC_FAST_PATH CapPtr< + T, + typename B::template with_wildness> + capptr_domesticate(typename Backend::LocalState* ls, CapPtr p) + { + static_assert(B::wildness == capptr::dimension::Wildness::Wild); + + static const size_t sz = sizeof( + std::conditional, 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>( + p.unsafe_ptr()); + } }; } diff --git a/src/backend/pagemap.h b/src/backend/pagemap.h index 7204162..9c770f0 100644 --- a/src/backend/pagemap.h +++ b/src/backend/pagemap.h @@ -205,6 +205,15 @@ namespace snmalloc body_opt = new_body; } + template + std::enable_if_t> get_bounds() + { + static_assert( + has_bounds_ == has_bounds, "Don't set SFINAE template parameter!"); + + return {base, size}; + } + /** * Get the number of entries. */ diff --git a/src/mem/localalloc.h b/src/mem/localalloc.h index 74d33b9..2e252d6 100644 --- a/src/mem/localalloc.h +++ b/src/mem/localalloc.h @@ -569,6 +569,11 @@ namespace snmalloc #ifdef SNMALLOC_PASS_THROUGH return external_alloc::malloc_usable_size(const_cast(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(