XXX: Added new dependency: `sha256_literal`. (TODO: Grab this, manage dependencies somehow..)
Added id.hh: `uuid` and related types & helpers.
Fortune for readpass's current commit: Future small blessing − 末小吉
// To prevent anon_raw_secmem being destroyed while there are still allocated values, the base class for the deleter for those values contains a refcount. e.g: `std::unique_ptr<T, deleter_for<T>>` where: `deleter_for<T> final : public deleter { virtual ~deleter_for(); ... };`, or `std::shared_ptr<T>`, where: `std::shared_ptr<value_with_deleter<T>>` aliases-ctor(`old, old->value_ptr()`) -> `std::shared_ptr<T>`
deleter::apply_delete(up);// If the dtor is trivial, ignore it and use default behaviour.
}else{
deleter::apply_delete(up,false);// Unlock the memory, but do *not* add it to this deleter's finalizer group.
apply_delete_typed(static_cast<T*>(up));// Apply the destructor for `T`
deleter::apply_finalizer_now({up});// Get `anon_raw_secmem` to deallocate the memory *now*, instead of at destruction.
}
}
};
template<typename>
structdeleter_for;
template<typename>
structdeleter_for_value;
public:
FrozenAllocator(FrozenAllocator&&)noexcept;
FrozenAllocator&operator=(FrozenAllocator&&);
@ -112,7 +77,45 @@ namespace alloc {
//std::shared_ptr<anon_raw_secmem> m_manager;
/// A map of values inside the allocator. This is destroyed in reverse order, meaning all the living values are destroyed *before* `m_manager`'d destruction deallocates them.
// A very basic typeid: Using the constexpr __PRETTY_FUNCTION__ array slicing trick we used for `exopt::util::type_name<T>()`, we can extract the unmangled, de-aliased type name T, we can then hash that at comptime, and give it static storage: Therefore __PRETTY_FUNCTION__ will not be given storage, but the resulting (far smaller, but still *almost* unique to each type name) hash, will be.
usingutil::type_name;
template<typenameT>
structtype_hash_of{
// Give *only* the computed hash static storage duration, not the type name.
/// Returns a (semi) unique SHA256 hash representing the type `T`.
///
/// NOTE: This hash is given static storage duration, but nothing else used to calculate it is. Therefore executable bloat is not a concern for values obtained from this function.
// Base class for all deallocations that happen within an `anon_raw_secmem` (managed, static, polymorphic, unmanaged, etc.) (TODO: See below, the base should be moved into the header so typed children can be templated...)
FrozenAllocator::deleter::~deleter(){
apply_finalizer_group();
//apply_finalizer_group(); // XXX: Do we actually need finalizer groups now? (see note below about `m_values`.
//TODO: auto&& fgroup = std::move(m_manager_ref->get_finalizer_group_for(finalizer_group_id())); // The *whole* finalizer group, *moved* from `m_manager_ref`. (which leaves finalizer_group for `this` empty now.)
//TODO: `bzero_explicit()` the memory from the allocations, then tell `anon_raw_secmem` to mark is as free.
}else{
//TODO: auto& fgroup = m_manager_ref->get_finalizer_group_ref_for(finalizer_group_id()); // The whole finalizer group, *referenced* from `m_manager_ref`. (which leaves finalizer_group for `this` intact, removal of pointers from the group will have to happen below manually.)
for(void*p:ptrs){
//TODO: Do the same as above, but only for pointers registered for finalizing in `ptrs`.
/// Instead of acting on pointers in `this`'s finalizer group, immediately get `anon_raw_secmem` to perform the deallocation and map-removal on these `ptrs`.
//(XXX: NOTE: `m_values` map removal *causes* this to be invoked, i.e: A value removed from the map calls `deleter::operator()(uniq_p)`, which then calls `apply_delete(uniq_p, true)`
// Lookup the allocation info for pointer `p`.
constauto&alloc=m_manager_ref->lookup_alloc(p);
if(UNLIKELY(!alloc))return{p,p};
// TODO: allow the allocation (the memory corresponding to `p` from `m_manager_ref`) to be mutable (`munlock()` it.)
// Get the full range (including alignment padding)
autoal_range=alloc.range();
// Then, if `clean == true` (default), `bzero_explicit()` the memory (range for `p` obtained from `m_manager_ref`.)
if(LIKELY(clean))scramble_memory(al_range);
// Return the range (or the end pointer of `p`'s range for use in / as an iterator.)
returnal_range;
}
// This is the *true manager* of the allocation arena, when it is destroyed, the memory is cleared
//XXX: Due to how this is managed via `shared_ptr<>`, it is UB for this to be called *before* all actual allocation of the memory are unallocated (via `deleter`, which they must *all* be managed by.
}
};
structFrozenAllocator::alloc_info{
id::uuidalloc_id;// ID of this allocation
id::unique_refowner;// Reference to the unique ID of the `anon_raw_secmem` that manages this allocation.
type_hash_ptrtype;// Static pointer to the `types::type_hash<T>()` result of the `T` that this allocation is. (Basic RTTI: `type_hash_t` should only exist in static storage, otherwise we use `type_hash_ref` or `type_hash_ptr`.)
/// vt_type_info: if info not null: return if `a` is type referred to in `info`, else if `type` not null: set `*type` to be type of `a`, return false if that is not possible with the other arguments given.
//TODO: How to create? Overloaded operator placement new, inside `alloc_info` or `anon_raw_secmem`? Since the storage for these are allocated and managed *by* `anon_raw_secmem`, that would make the most sense I think... `alloc_info` holds the pointer to the specific allocation, its ID, etc; stuff for ordered allocation lookup. This is managed (entirely) by `anon_raw_secmem`, and `std::unique_ptr<alloc_value, anon_raw_secmem::deleter>` ensures it is not deleted naturally, but only removed from `anon_raw_secmem`.
//! Basic RTTI impl that holds type-erased, alignment padded values and gives out aligned void* pointers to it.
//! NOTE: This class does *not* apply any destructor when destroyed, `anon_raw_secmem::deleter` should be used for that.
struct{
struct{
vt_ctor_create;
vt_copy_copy;
vt_move_move;
vt_destroy_destroy;
vt_this_this;
vt_type_info_typeinfo;
// We don't need the others, they can be constructed by combining calls to these. (e.g.: assign_copy(new, old) = `destroy(old), copy(new, old)`.)