From 313a682faf0e8eb1e4bcd36543668e6c21e9c157 Mon Sep 17 00:00:00 2001 From: Nathaniel Filardo Date: Tue, 30 Mar 2021 12:19:25 +0100 Subject: [PATCH] SP: capptr_bound_chunkd, capptr_chunk_from_chunkd These helpers centralize the handling of CBChunkD-related flows --- src/mem/ptrhelpers.h | 98 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/mem/ptrhelpers.h diff --git a/src/mem/ptrhelpers.h b/src/mem/ptrhelpers.h new file mode 100644 index 0000000..e43119d --- /dev/null +++ b/src/mem/ptrhelpers.h @@ -0,0 +1,98 @@ +#pragma once + +#include "../aal/aal.h" +#include "../ds/ptrwrap.h" +#include "allocconfig.h" + +namespace snmalloc +{ + /* + * At various points, we do pointer math on high-authority pointers to find + * some metadata. `capptr_bound_chunkd` and `capptr_chunk_from_chunkd` + * encapsulate the notion that the result of these accesses is left unbounded + * in non-debug builds, because most codepaths do not reveal these pointers or + * any progeny to the application. However, in some cases we have already + * (partially) bounded these high-authority pointers (to CBChunk) and wish to + * preserve this annotation (rather than always returning a CBChunkD-annotated + * pointer); `capptr_bound_chunkd_bounds` does the computation for us and is + * used in the signatures of below and in those of wrappers around them. + */ + + template + constexpr capptr_bounds capptr_bound_chunkd_bounds() + { + switch (B) + { + case CBArena: + return CBChunkD; + case CBChunkD: + return CBChunkD; + case CBChunk: + return CBChunk; + } + } + + /** + * Construct an CapPtr from an CapPtr or + * CapPtr input. For an CapPtr input, simply pass + * it through (preserving the static notion of bounds). + * + * Applies bounds on debug builds, otherwise is just sleight of hand. + * + * Requires that `p` point at a multiple of `sz` (that is, at the base of a + * highly-aligned object) to avoid representability issues. + */ + template + SNMALLOC_FAST_PATH CapPtr()> + capptr_bound_chunkd(CapPtr p, size_t sz) + { + static_assert(B == CBArena || B == CBChunkD || B == CBChunk); + SNMALLOC_ASSERT((address_cast(p) % sz) == 0); + +#ifndef NDEBUG + // On Debug builds, apply bounds if not already there + if constexpr (B == CBArena) + return Aal::capptr_bound(p, sz); + else // quiesce MSVC's warnings about unreachable code below +#endif + { + UNUSED(sz); + return CapPtr()>(p.unsafe_capptr); + } + } + + /** + * Apply bounds that might not have been applied when constructing an + * CapPtr. That is, on non-debug builds, apply bounds; debug + * builds have already had them applied. + * + * Requires that `p` point at a multiple of `sz` (that is, at the base of a + * highly-aligned object) to avoid representability issues. + */ + template + SNMALLOC_FAST_PATH CapPtr + capptr_chunk_from_chunkd(CapPtr p, size_t sz) + { + SNMALLOC_ASSERT((address_cast(p) % sz) == 0); + +#ifndef NDEBUG + // On debug builds, CBChunkD are already bounded as if CBChunk. + UNUSED(sz); + return CapPtr(p.unsafe_capptr); +#else + // On non-debug builds, apply bounds now, as they haven't been already. + return Aal::capptr_bound(p, sz); +#endif + } + + /** + * Very rarely, while debugging, it's both useful and acceptable to forget + * that we have applied chunk bounds to something. + */ + template + SNMALLOC_FAST_PATH CapPtr + capptr_debug_chunkd_from_chunk(CapPtr p) + { + return CapPtr(p.unsafe_capptr); + } +} // namespace snmalloc