mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-17 21:00:37 +02:00
fextl: Add pmr default resource
This commit is contained in:
1 parent
7150c532f3
commit
79f7baffe3
3 files changed
+226
-1
No files matched your search
+9
-1
@@ -2,6 +2,7 @@
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/fextl/memory_resource.h>
|
||||
#include <FEXHeaderUtils/Syscalls.h>
|
||||
#include <FEXHeaderUtils/TypeDefines.h>
|
||||
|
||||
@@ -32,6 +33,13 @@ extern "C" {
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace fextl::pmr {
|
||||
static fextl::pmr::default_resource FEXDefaultResource;
|
||||
std::pmr::memory_resource* get_default_resource() {
|
||||
return &FEXDefaultResource;
|
||||
}
|
||||
}
|
||||
|
||||
namespace FEXCore::Allocator {
|
||||
MMAP_Hook mmap {::mmap};
|
||||
MUNMAP_Hook munmap {::munmap};
|
||||
@@ -63,7 +71,7 @@ namespace FEXCore::Allocator {
|
||||
using GLIBC_REALLOC_Hook = void*(*)(void*, size_t, const void *caller);
|
||||
using GLIBC_FREE_Hook = void(*)(void*, const void *caller);
|
||||
|
||||
std::unique_ptr<Alloc::HostAllocator> Alloc64{};
|
||||
fextl::unique_ptr<Alloc::HostAllocator> Alloc64{};
|
||||
|
||||
void *FEX_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
|
||||
void *Result = Alloc64->Mmap(addr, length, prot, flags, fd, offset);
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" {
|
||||
#ifdef GLIBC_ALLOCATOR_FAULT
|
||||
// glibc allocator faulting. If anything uses a glibc allocator symbol then cause a fault.
|
||||
// Ensures that FEX only ever allocates memory through its allocator routines.
|
||||
// If thunks are enabled then this should crash immediately. Thunks should still go through glibc allocator.
|
||||
// These need to be symbol definitions /only/, don't let their visibility to the rest of the source happen.
|
||||
#define GLIBC_ALIAS_FUNCTION(func) __attribute__((alias(#func), visibility("default")))
|
||||
extern void *__libc_calloc(size_t, size_t);
|
||||
void *calloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_calloc);
|
||||
|
||||
extern void __libc_free(void*);
|
||||
void free(void*) GLIBC_ALIAS_FUNCTION(fault_free);
|
||||
|
||||
extern void *__libc_malloc(size_t);
|
||||
void *malloc(size_t) GLIBC_ALIAS_FUNCTION(fault_malloc);
|
||||
|
||||
extern void *__libc_memalign(size_t, size_t);
|
||||
void *memalign(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_memalign);
|
||||
|
||||
extern void *__libc_realloc(void*, size_t);
|
||||
void *realloc(void*, size_t) GLIBC_ALIAS_FUNCTION(fault_realloc);
|
||||
|
||||
extern void *__libc_valloc(size_t);
|
||||
void *valloc(size_t) GLIBC_ALIAS_FUNCTION(fault_valloc);
|
||||
|
||||
extern int __posix_memalign(void **, size_t, size_t);
|
||||
int posix_memalign(void **, size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_posix_memalign);
|
||||
|
||||
extern size_t __malloc_usable_size(void*);
|
||||
size_t malloc_usable_size(void*) GLIBC_ALIAS_FUNCTION(fault_malloc_usable_size);
|
||||
|
||||
// Reuse __libc_memalign
|
||||
void *aligned_alloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_aligned_alloc);
|
||||
}
|
||||
|
||||
namespace FEXCore::Allocator {
|
||||
static bool Evaluate{};
|
||||
thread_local uint64_t SkipEvalForThread{};
|
||||
|
||||
CALLOC_Hook calloc_ptr = __libc_calloc;
|
||||
FREE_Hook free_ptr = __libc_free;
|
||||
MALLOC_Hook malloc_ptr = __libc_malloc;
|
||||
MEMALIGN_Hook memalign_ptr = __libc_memalign;
|
||||
REALLOC_Hook realloc_ptr = __libc_realloc;
|
||||
VALLOC_Hook valloc_ptr = __libc_valloc;
|
||||
POSIX_MEMALIGN_Hook posix_memalign_ptr = ::posix_memalign;
|
||||
MALLOC_USABLE_SIZE_Hook malloc_usable_size_ptr = ::malloc_usable_size;
|
||||
ALIGNED_ALLOC_Hook aligned_alloc_ptr = __libc_memalign;
|
||||
|
||||
YesIKnowImNotSupposedToUseTheGlibcAllocator::YesIKnowImNotSupposedToUseTheGlibcAllocator() {
|
||||
++SkipEvalForThread;
|
||||
}
|
||||
|
||||
YesIKnowImNotSupposedToUseTheGlibcAllocator::~YesIKnowImNotSupposedToUseTheGlibcAllocator() {
|
||||
--SkipEvalForThread;
|
||||
}
|
||||
|
||||
FEX_DEFAULT_VISIBILITY void YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable() {
|
||||
// Just set it to half of its maximum value so it never wraps back around.
|
||||
SkipEvalForThread = std::numeric_limits<decltype(SkipEvalForThread)>::max() / 2;
|
||||
}
|
||||
|
||||
void SetupFaultEvaluate() {
|
||||
Evaluate = true;
|
||||
}
|
||||
|
||||
void ClearFaultEvaluate() {
|
||||
Evaluate = false;
|
||||
}
|
||||
|
||||
void EvaluateReturnAddress(void* Return) {
|
||||
if (!Evaluate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SkipEvalForThread) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't know where we are when allocating. Make sure to be safe and generate the string on the stack.
|
||||
char Tmp[512];
|
||||
auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast<uint64_t>(Return));
|
||||
Tmp[Res.size] = 0;
|
||||
write(STDERR_FILENO, Tmp, Res.size);
|
||||
LogMan::Msg::AFmt(Tmp);
|
||||
FEX_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void *fault_calloc(size_t n, size_t size) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::calloc_ptr(n, size);
|
||||
}
|
||||
void fault_free(void* ptr) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
FEXCore::Allocator::free_ptr(ptr);
|
||||
}
|
||||
void *fault_malloc(size_t size) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::malloc_ptr(size);
|
||||
}
|
||||
void *fault_memalign(size_t align, size_t s) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::memalign_ptr(align, s);
|
||||
}
|
||||
void *fault_realloc(void* ptr, size_t size) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::realloc_ptr(ptr, size);
|
||||
}
|
||||
void *fault_valloc(size_t size) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::valloc_ptr(size);
|
||||
}
|
||||
int fault_posix_memalign(void ** r, size_t a, size_t s) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::posix_memalign_ptr(r, a, s);
|
||||
}
|
||||
size_t fault_malloc_usable_size(void *ptr) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::malloc_usable_size_ptr(ptr);
|
||||
}
|
||||
void *fault_aligned_alloc(size_t a, size_t s) {
|
||||
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
|
||||
return FEXCore::Allocator::aligned_alloc_ptr(a, s);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
#include <FEXCore/Utils/MathUtils.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/fextl/allocator.h>
|
||||
|
||||
#include <memory_resource>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace fextl {
|
||||
namespace pmr {
|
||||
class default_resource : public std::pmr::memory_resource {
|
||||
private:
|
||||
void* do_allocate( std::size_t bytes, std::size_t alignment ) override {
|
||||
return FEXCore::Allocator::memalign(alignment, bytes);
|
||||
}
|
||||
|
||||
void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override {
|
||||
return FEXCore::Allocator::free(p);
|
||||
}
|
||||
|
||||
bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override {
|
||||
return this == &other;
|
||||
}
|
||||
};
|
||||
|
||||
FEX_DEFAULT_VISIBILITY std::pmr::memory_resource* get_default_resource();
|
||||
|
||||
/**
|
||||
* @brief This is similar to the std::pmr::monotonic_buffer_resource.
|
||||
*
|
||||
* The difference is that class doesn't have ownership of the backing memory and
|
||||
* it also doesn't have any growth factor.
|
||||
*
|
||||
* If the amount of memory allocated is overrun then this will overwrite memory unless assertions are enabled.
|
||||
*
|
||||
* Ensure that you know how much memory you're going to use before using this class.
|
||||
*/
|
||||
class fixed_size_monotonic_buffer_resource final : public std::pmr::memory_resource {
|
||||
public:
|
||||
fixed_size_monotonic_buffer_resource(void* Base, size_t Size)
|
||||
: Ptr {reinterpret_cast<uint64_t>(Base)}
|
||||
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
||||
, PtrEnd {reinterpret_cast<uint64_t>(Base) + Size}
|
||||
, Size {Size}
|
||||
#endif
|
||||
{}
|
||||
void* do_allocate( std::size_t bytes, std::size_t alignment ) override {
|
||||
uint64_t NewPtr = FEXCore::AlignUp((uint64_t)Ptr, alignment);
|
||||
Ptr = NewPtr + bytes;
|
||||
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
||||
if (Ptr >= PtrEnd) {
|
||||
LogMan::Msg::AFmt("Fail: Only allocated: {} ({} this time) bytes. Tried allocating at ptr offset: {}.\n",
|
||||
Size,
|
||||
bytes,
|
||||
(uint64_t)(Ptr - (PtrEnd - Size)));
|
||||
FEX_TRAP_EXECUTION;
|
||||
}
|
||||
#endif
|
||||
return reinterpret_cast<void*>(NewPtr);
|
||||
}
|
||||
|
||||
void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override {
|
||||
// noop
|
||||
}
|
||||
|
||||
bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override {
|
||||
return this == &other;
|
||||
}
|
||||
private:
|
||||
uint64_t Ptr;
|
||||
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
||||
uint64_t PtrEnd;
|
||||
size_t Size;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user