Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

override add OpenBSD's malloc_conceal API proposal. #439

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/backend/globalconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ namespace snmalloc
* from the operating system and expects to manage memory anywhere in the
* address space.
*/
class Globals final : public BackendAllocator<Pal, false>
template<CoreDump CDM = DoDump>
class GlobalsConfig final : public BackendAllocator<Pal<CDM>, false>
{
public:
using GlobalPoolState = PoolState<CoreAllocator<Globals>>;
using GlobalPoolState = PoolState<CoreAllocator<GlobalsConfig<CDM>>>;

private:
using Backend = BackendAllocator<Pal, false>;
using Backend = BackendAllocator<Pal<CDM>, false>;
SNMALLOC_REQUIRE_CONSTINIT
inline static ChunkAllocatorState chunk_allocator_state;

Expand Down Expand Up @@ -76,7 +77,7 @@ namespace snmalloc
return;

LocalEntropy entropy;
entropy.init<Pal>();
entropy.init<Pal<CDM>>();
// Initialise key for remote deallocation lists
key_global = FreeListKey(entropy.get_free_list_key());

Expand Down Expand Up @@ -104,4 +105,7 @@ namespace snmalloc
snmalloc::register_clean_up();
}
};

using Globals = GlobalsConfig<DoDump>;
using GlobalsNd = GlobalsConfig<DontDump>;
} // namespace snmalloc
2 changes: 1 addition & 1 deletion src/mem/chunkallocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace snmalloc
/**
* How many slab sizes that can be provided.
*/
constexpr size_t NUM_SLAB_SIZES = Pal::address_bits - MIN_CHUNK_BITS;
constexpr size_t NUM_SLAB_SIZES = Pal<DoDump>::address_bits - MIN_CHUNK_BITS;

/**
* Used to ensure the per slab meta data is large enough for both use cases.
Expand Down
2 changes: 1 addition & 1 deletion src/mem/entropy.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace snmalloc
std::enable_if_t<!pal_supports<Entropy, PAL>, uint64_t> get_entropy64()
{
#ifdef SNMALLOC_PLATFORM_HAS_GETENTROPY
return DefaultPal::get_entropy64();
return DefaultPal<DoDump>::get_entropy64();
#else
std::random_device rd;
uint64_t a = rd();
Expand Down
4 changes: 2 additions & 2 deletions src/mem/scopedalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace snmalloc
/**
* The allocator that this wrapper will use.
*/
Alloc alloc;
Alloc<> alloc;

/**
* Constructor. Claims an allocator from the global pool
Expand Down Expand Up @@ -66,7 +66,7 @@ namespace snmalloc
* Arrow operator, allows methods exposed by `Alloc` to be called on the
* wrapper.
*/
Alloc* operator->()
Alloc<>* operator->()
{
return &alloc;
}
Expand Down
2 changes: 1 addition & 1 deletion src/mem/sizeclasstable.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace snmalloc

// Large classes range from [MAX_SMALL_SIZECLASS_SIZE, ADDRESS_SPACE).
static constexpr size_t NUM_LARGE_CLASSES =
Pal::address_bits - MAX_SMALL_SIZECLASS_BITS;
Pal<DoDump>::address_bits - MAX_SMALL_SIZECLASS_BITS;

// How many bits are required to represent either a large or a small
// sizeclass.
Expand Down
7 changes: 4 additions & 3 deletions src/mem/threadalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace snmalloc
static void register_cleanup() {}

public:
static SNMALLOC_FAST_PATH Alloc& get()
static SNMALLOC_FAST_PATH Alloc<>& get()
{
return ThreadAllocExternal::get();
}
Expand Down Expand Up @@ -88,9 +88,10 @@ namespace snmalloc
* It can be used during thread teardown, but its performance will be
* less good.
*/
static SNMALLOC_FAST_PATH Alloc& get()
template<CoreDump CDM = DoDump>
static SNMALLOC_FAST_PATH Alloc<>& get()
{
SNMALLOC_REQUIRE_CONSTINIT static thread_local Alloc alloc;
SNMALLOC_REQUIRE_CONSTINIT static thread_local Alloc<> alloc;
return alloc;
}
};
Expand Down
36 changes: 36 additions & 0 deletions src/override/malloc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,31 @@ extern "C"
ThreadAlloc::get().dealloc(ptr);
}

SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(malloc_conceal)(size_t size)
{
size_t sz = round_size(size);
return ThreadAlloc::get<DontDump>().alloc(sz);
}

SNMALLOC_EXPORT void SNMALLOC_NAME_MANGLE(freezero)(void* p, size_t size)
{
if (SNMALLOC_UNLIKELY(p == nullptr))
{
return;
}

auto& a = ThreadAlloc::get<CoreDump::DontDump>();
size_t sz = bits::min(size, a.alloc_size(p));

/* we are not trying to be fast here, but disallowing to potentially
* optimize away the memset call */

void* (*volatile memset_fn)(void*, int, size_t) = memset;
memset_fn(p, 0, sz);

a.dealloc(p);
}

/**
* Clang was helpfully inlining the constant return value, and
* thus converting from a tail call to an ordinary call.
Expand All @@ -54,6 +79,17 @@ extern "C"
return ThreadAlloc::get().alloc<ZeroMem::YesZero>(sz);
}

SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(calloc_conceal)(size_t nmemb, size_t size)
{
bool overflow = false;
size_t sz = round_size(bits::umul(size, nmemb, overflow));
if (SNMALLOC_UNLIKELY(overflow))
{
return SNMALLOC_NAME_MANGLE(snmalloc_set_error)();
}
return ThreadAlloc::get<CoreDump::DontDump>().alloc<ZeroMem::YesZero>(sz);
}

SNMALLOC_EXPORT
size_t SNMALLOC_NAME_MANGLE(malloc_usable_size)(
MALLOC_USABLE_SIZE_QUALIFIER void* ptr)
Expand Down
2 changes: 1 addition & 1 deletion src/override/memcpy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ namespace
alloc.template external_pointer<Start>(p),
alloc.template external_pointer<OnePastEnd>(p),
len);
Pal::error(buffer.data());
Pal<>::error(buffer.data());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/override/override.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// The default configuration for snmalloc is used if alternative not defined
namespace snmalloc
{
using Alloc = snmalloc::LocalAllocator<snmalloc::Globals>;
template<SNMALLOC_CONCEPT(snmalloc::ConceptBackendGlobals) GC = snmalloc::Globals> using Alloc = snmalloc::LocalAllocator<GC>;
} // namespace snmalloc
#endif

Expand Down
14 changes: 8 additions & 6 deletions src/pal/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
namespace snmalloc
{
#if !defined(OPEN_ENCLAVE) || defined(OPEN_ENCLAVE_SIMULATION)
template<CoreDump CDM = DoDump>
using DefaultPal =
# if defined(_WIN32)
PALWindows;
# elif defined(__APPLE__)
PALApple<>;
# elif defined(__linux__)
PALLinux;
PALLinux<CDM>;
# elif defined(FreeBSD_KERNEL)
PALFreeBSDKernel;
# elif defined(__FreeBSD__)
Expand All @@ -52,22 +53,23 @@ namespace snmalloc
# endif
#endif

template<CoreDump CDM = DoDump>
using Pal =
#if defined(SNMALLOC_MEMORY_PROVIDER)
PALPlainMixin<SNMALLOC_MEMORY_PROVIDER>;
#elif defined(OPEN_ENCLAVE)
PALOpenEnclave;
#else
DefaultPal;
DefaultPal<CDM>;
#endif

[[noreturn]] SNMALLOC_SLOW_PATH inline void error(const char* const str)
{
Pal::error(str);
Pal<DoDump>::error(str);
}

// Used to keep Superslab metadata committed.
static constexpr size_t OS_PAGE_SIZE = Pal::page_size;
static constexpr size_t OS_PAGE_SIZE = Pal<DoDump>::page_size;

/**
* Perform platform-specific adjustment of return pointers.
Expand All @@ -76,7 +78,7 @@ namespace snmalloc
* disruption to PALs for platforms that do not support StrictProvenance AALs.
*/
template<
typename PAL = Pal,
typename PAL = Pal<>,
typename AAL = Aal,
typename T,
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
Expand All @@ -89,7 +91,7 @@ namespace snmalloc
}

template<
typename PAL = Pal,
typename PAL = Pal<>,
typename AAL = Aal,
typename T,
SNMALLOC_CONCEPT(capptr::ConceptBound) B>
Expand Down
12 changes: 12 additions & 0 deletions src/pal/pal_consts.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ namespace snmalloc
YesZero
};

enum CoreDump
{
/**
* Default mode, memory are being dumped into a core file
*/
DoDump,
/**
* Memory content not dumped into a core file
*/
DontDump,
};

/**
* Default Tag ID for the Apple class
*/
Expand Down
22 changes: 19 additions & 3 deletions src/pal/pal_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ extern "C" int puts(const char* str);

namespace snmalloc
{
class PALLinux : public PALPOSIX<PALLinux>
template<CoreDump CDM>
class PALLinux : public PALPOSIX<PALLinux<CDM>>
{
public:
/**
Expand All @@ -22,10 +23,10 @@ namespace snmalloc
*
* We always make sure that linux has entropy support.
*/
static constexpr uint64_t pal_features = PALPOSIX::pal_features | Entropy;
static constexpr uint64_t pal_features = PALPOSIX<PALLinux<CDM>>::pal_features | Entropy;

static constexpr size_t page_size =
Aal::aal_name == PowerPC ? 0x10000 : PALPOSIX::page_size;
Aal::aal_name == PowerPC ? 0x10000 : PALPOSIX<PALLinux<CDM>>::page_size;

/**
* Linux requires an explicit no-reserve flag in `mmap` to guarantee lazy
Expand Down Expand Up @@ -65,6 +66,21 @@ namespace snmalloc
}
}

static void* reserve(size_t size) noexcept
{
void* p = PALPOSIX<PALLinux<CDM>>::reserve(size);
if (p)
{
if constexpr (CDM == DontDump)
{
SNMALLOC_ASSERT(is_aligned_block<page_size>(p, size));
madvise(p, size, MADV_DONTDUMP);
}
}

return p;
}

static void notify_not_using(void* p, size_t size) noexcept
{
SNMALLOC_ASSERT(is_aligned_block<page_size>(p, size));
Expand Down
2 changes: 1 addition & 1 deletion src/snmalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// The default configuration for snmalloc
namespace snmalloc
{
using Alloc = snmalloc::LocalAllocator<snmalloc::Globals>;
template<SNMALLOC_CONCEPT(snmalloc::ConceptBackendGlobals) GC = snmalloc::Globals> using Alloc = snmalloc::LocalAllocator<GC>;
}

// User facing API surface, needs to know what `Alloc` is.
Expand Down
10 changes: 5 additions & 5 deletions src/test/func/domestication/domestication.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ int main()
# define SNMALLOC_PROVIDE_OWN_CONFIG
namespace snmalloc
{
class CustomGlobals : public BackendAllocator<Pal, false>
class CustomGlobals : public BackendAllocator<Pal<>, false>
{
public:
using GlobalPoolState = PoolState<CoreAllocator<CustomGlobals>>;
Expand Down Expand Up @@ -102,7 +102,7 @@ namespace snmalloc
}
};

using Alloc = LocalAllocator<CustomGlobals>;
template<SNMALLOC_CONCEPT(ConceptBackendGlobals) GC = CustomGlobals> using Alloc = LocalAllocator<GC>;
}

# define SNMALLOC_NAME_MANGLE(a) test_##a
Expand All @@ -114,18 +114,18 @@ int main()
snmalloc::CustomGlobals::domesticate_count = 0;

LocalEntropy entropy;
entropy.init<Pal>();
entropy.init<Pal<>>();
key_global = FreeListKey(entropy.get_free_list_key());

auto alloc1 = new Alloc();
auto alloc1 = new Alloc<>();

// Allocate from alloc1; the size doesn't matter a whole lot, it just needs to
// be a small object and so definitely owned by this allocator rather.
auto p = alloc1->alloc(48);
std::cout << "Allocated p " << p << std::endl;

// Put that free object on alloc1's remote queue
auto alloc2 = new Alloc();
auto alloc2 = new Alloc<>();
alloc2->dealloc(p);
alloc2->flush();

Expand Down
6 changes: 3 additions & 3 deletions src/test/func/fixed_region/fixed_region.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

using namespace snmalloc;

using CustomGlobals = FixedGlobals<PALNoAlloc<DefaultPal>>;
using CustomGlobals = FixedGlobals<PALNoAlloc<DefaultPal<DoDump>>>;
using FixedAlloc = LocalAllocator<CustomGlobals>;

int main()
Expand All @@ -23,8 +23,8 @@ int main()
// It is also large enough for the example to run in.
// For 1MiB superslabs, SUPERSLAB_BITS + 4 is not big enough for the example.
auto size = bits::one_at_bit(28);
auto oe_base = Pal::reserve(size);
Pal::notify_using<NoZero>(oe_base, size);
auto oe_base = Pal<>::reserve(size);
Pal<>::notify_using<NoZero>(oe_base, size);
auto oe_end = pointer_offset(oe_base, size);
std::cout << "Allocated region " << oe_base << " - "
<< pointer_offset(oe_base, size) << std::endl;
Expand Down
Loading