You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
4.1 KiB

//! Custom allocation framekwork for frozen (RO) and/or secure allocations, shared allocations, aliased allocation, etc. (polymorphic.)
#ifndef _ALLOC_H
#define _ALLOC_H
#ifdef __cplusplus
#include <memory>
#include <pair>
#endif
#include "constraints.hh"
#include "types.h"
#include "macros.h"
LINK_START(C)
typedef struct base_allocator alloc_t;
//TODO: C API anonlogue for allocator interface below.
LINK_END
#if $CXX
extern "C" {
struct base_allocator {
//TODO: Allocator interface...
virtual ~base_allocator();
}
}
namespace alloc {
class FrozenAllocator : public alloc_t {
struct _impl;
protected:
struct anon_raw_secmem;
// Untyped deleter
struct deleter {
friend class anon_raw_secmem;
constexpr deleter(const deleter&) noexcept = default;
constexpr deleter& operator=(const deleter&) noexcept = default;
constexpr deleter(deleter&&) noexcept = default;
constexpr deleter& operator=(deleter&&) noexcept = default;
[[gnu::nonnull(2)]]
constexpr void operator()(void* restrict p) const noexcept { apply_delete(p); }
virtual ~deleter();
protected:
explicit deleter(std::shared_ptr<anon_raw_secmem>&& p);
[[gnu::nonnull(2)]]
virtual std::pair<void*> apply_delete(void* restrict, bool = true) const noexcept;
virtual void scramble_memory(std::initializer_list<std::pair<void*>> ptrs) const noexcept;
inline void scramble_memory(std::pair<void*> ptr) const noexcept { return scramble_memory({ ptr }); }
// 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>`
std::shared_ptr<anon_raw_secmem> m_manager_ref;
};
struct alloc_vt;
struct alloc_info;
struct alloc_value;
template<typename>
struct deleter_for;
template<typename>
struct deleter_for_value;
public:
FrozenAllocator(FrozenAllocator &&) noexcept;
FrozenAllocator& operator=(FrozenAllocator &&);
FrozenAllocator(const FrozenAllocator&) = delete;
FrozenAllocator& operator=(const FrozenAllocator&) = delete;
virtual ~FrozenAllocator();
private:
std::unique_ptr<_impl> inner_;
/// Manages everything about the actual allocations
//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.
//std::map<alloc_info, std::unique_ptr<alloc_value, deleter>> m_values;
};
template<typename T>
struct FrozenAllocator::deleter_for
: virtual deleter
{
inline deleter_for(std::shared_ptr<anon_raw_secmem>&& m)
: deleter(std::move(m)) {}
virtual ~deleter_for() = default; // This will use deleter's dtor to remove allocations.
[[gnu::nonnull(2)]]
inline void operator()(T* ptr) const noexcept { apply_delete(deleter::erase_type_unsafe(ptr)); }
protected:
inline virtual void apply_delete_typed(T* ptr) const noexcept {
ptr->~T();
}
private:
[[gnu::nonnull(2)]]
inline std::pair<void*> apply_delete(void* restrict up) const noexcept override final {
if constexpr(std::is_trivially_destructible_v<T>) {
return deleter::apply_delete(up); // If the dtor is trivial, ignore it and use default behaviour.
} else {
auto pair = deleter::apply_delete(up, false); // Unlock the memory and remove the allocation from `anon_raw_secmem`, but do *not* bzero it.
apply_delete_typed(static_cast<T*>(up)); // Apply the destructor for `T` to the alligned pointer `up`.
deleter::scramble_memory(pair); // *now* bzero the unaligned pointer (full range, including alignment padding.)
return pair;
}
}
};
template<typename T>
struct FrozenAllocator::deleter_for_value final : deleter_for<T> {
//TODO: Re-work this? Is it useful? Is it needed?
inline virtual ~deleter_for_value() {
deleter_for<T>::apply_delete(m_value_ptr);
}
private:
T* m_value_ptr;
};
}
#endif
#endif /* _ALLOC_H */