From 543e2db3e1eddbf1f446f3d8a88e71e74bccc70f Mon Sep 17 00:00:00 2001 From: naitro2010 <108594252+naitro2010@users.noreply.github.com> Date: Fri, 25 Jul 2025 03:08:05 -0700 Subject: [PATCH 1/3] attempt to workaround double free by adding memory cookie --- src/patches/memorymanager.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/patches/memorymanager.cpp b/src/patches/memorymanager.cpp index 035c7e4..360e761 100644 --- a/src/patches/memorymanager.cpp +++ b/src/patches/memorymanager.cpp @@ -80,22 +80,26 @@ namespace namespace MemoryManager { - void* Allocate(RE::MemoryManager*, std::size_t a_size, std::uint32_t a_alignment, bool a_alignmentRequired) - { - if (a_size > 0) - return a_alignmentRequired ? - scalable_aligned_malloc(a_size, a_alignment) : - scalable_malloc(a_size); - else - return g_trash; + void *Allocate(RE::MemoryManager *, std::size_t a_size, std::uint32_t a_alignment, bool a_alignmentRequired) { + if (a_size > 0) { + void *return_ptr = a_alignmentRequired ? scalable_aligned_malloc(a_size + 0x100, a_alignment) : scalable_malloc(a_size + 0x100); + uint64_t *return_ptr_offset = (uint64_t *) (((uint64_t) return_ptr) + 0x100); + *(uint64_t *) return_ptr = 0x1337DEADDEAD1337; + return (void *) return_ptr_offset; + } + else return g_trash; } - void Deallocate(RE::MemoryManager*, void* a_mem, bool a_alignmentRequired) - { - if (a_mem != g_trash) - a_alignmentRequired ? - scalable_aligned_free(a_mem) : - scalable_free(a_mem); + void Deallocate(RE::MemoryManager *, void *a_mem, bool a_alignmentRequired) { + if (a_mem != g_trash) { + if (a_mem) { + std::atomic *original_mem = (std::atomic *) (((uint64_t) a_mem) - 0x100); + uint64_t expected = 0x1337DEADDEAD1337; + if (original_mem->compare_exchange_strong(expected, (uint64_t) 0x0)) { + a_alignmentRequired ? scalable_aligned_free(original_mem) : scalable_free(original_mem); + } + } + } } void* Reallocate(RE::MemoryManager* a_self, void* a_oldMem, std::size_t a_newSize, std::uint32_t a_alignment, bool a_alignmentRequired) From 26f17546a33b0a6561ddfe37b4799af83f64c386 Mon Sep 17 00:00:00 2001 From: naitro2010 <108594252+naitro2010@users.noreply.github.com> Date: Fri, 25 Jul 2025 03:17:59 -0700 Subject: [PATCH 2/3] add reallocate and scrap heap support --- src/patches/memorymanager.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/patches/memorymanager.cpp b/src/patches/memorymanager.cpp index 360e761..4f15363 100644 --- a/src/patches/memorymanager.cpp +++ b/src/patches/memorymanager.cpp @@ -102,16 +102,22 @@ namespace } } - void* Reallocate(RE::MemoryManager* a_self, void* a_oldMem, std::size_t a_newSize, std::uint32_t a_alignment, bool a_alignmentRequired) - { + void *Reallocate(RE::MemoryManager *a_self, void *a_oldMem, std::size_t a_newSize, std::uint32_t a_alignment, + bool a_alignmentRequired) { if (a_oldMem == g_trash) return Allocate(a_self, a_newSize, a_alignment, a_alignmentRequired); - else - return a_alignmentRequired ? - scalable_aligned_realloc(a_oldMem, a_newSize, a_alignment) : - scalable_realloc(a_oldMem, a_newSize); + else if (a_oldMem) { + void *original_mem = (std::atomic *) (((uint64_t) a_oldMem) - 0x100); + std::atomic *original_cookie = (std::atomic *) (((uint64_t) a_oldMem) - 0x100); + uint64_t expected = 0x1337DEADDEAD1337; + if (original_cookie->compare_exchange_strong(expected, (uint64_t) 0x1337DEADDEAD1337)) { + void *new_mem = a_alignmentRequired ? scalable_aligned_realloc(original_mem, a_newSize + 0x100, a_alignment) + : scalable_realloc(original_mem, a_newSize + 0x100); + *(uint64_t *) new_mem = (uint64_t) 0x1337DEADDEAD1337; + return (void *) (((uint64_t) new_mem) + 0x100); + } + } } - void ReplaceAllocRoutines() { using tuple_t = std::tuple; @@ -162,9 +168,7 @@ namespace { void* Allocate(RE::ScrapHeap*, std::size_t a_size, std::size_t a_alignment) { - return a_size > 0 ? - scalable_aligned_malloc(a_size, a_alignment) : - g_trash; + return MemoryManager::Allocate(nullptr,a_size,a_alignment,true); } RE::ScrapHeap* Ctor(RE::ScrapHeap* a_this) @@ -176,8 +180,7 @@ namespace void Deallocate(RE::ScrapHeap*, void* a_mem) { - if (a_mem != g_trash) - scalable_aligned_free(a_mem); + return MemoryManager::Deallocate(nullptr,a_mem,true); } void WriteHooks() From c96e373802a6a9c785dba083dc5fc32510d8d22e Mon Sep 17 00:00:00 2001 From: Andrej E Baranov Date: Fri, 25 Jul 2025 22:37:38 +0700 Subject: [PATCH 3/3] compile --- src/patches/memorymanager.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/patches/memorymanager.cpp b/src/patches/memorymanager.cpp index 4f15363..32dc30e 100644 --- a/src/patches/memorymanager.cpp +++ b/src/patches/memorymanager.cpp @@ -85,6 +85,7 @@ namespace void *return_ptr = a_alignmentRequired ? scalable_aligned_malloc(a_size + 0x100, a_alignment) : scalable_malloc(a_size + 0x100); uint64_t *return_ptr_offset = (uint64_t *) (((uint64_t) return_ptr) + 0x100); *(uint64_t *) return_ptr = 0x1337DEADDEAD1337; + //logger::trace("MemoryManagerStats::Allocate ptr {} (internal ptr {}) diff {}.", reinterpret_cast(return_ptr_offset), reinterpret_cast(return_ptr), reinterpret_cast(return_ptr_offset) - reinterpret_cast(return_ptr)); return (void *) return_ptr_offset; } else return g_trash; @@ -96,8 +97,12 @@ namespace std::atomic *original_mem = (std::atomic *) (((uint64_t) a_mem) - 0x100); uint64_t expected = 0x1337DEADDEAD1337; if (original_mem->compare_exchange_strong(expected, (uint64_t) 0x0)) { + //logger::trace("MemoryManagerStats::Deallocate ptr {} (internal ptr {}) diff {}.", reinterpret_cast(a_mem), reinterpret_cast(original_mem), reinterpret_cast(a_mem) - reinterpret_cast(original_mem)); a_alignmentRequired ? scalable_aligned_free(original_mem) : scalable_free(original_mem); } + else { + logger::warn("MemoryManager::Deallocate error 202: already deallocated for addr {}.", reinterpret_cast(a_mem)); + } } } } @@ -108,15 +113,24 @@ namespace return Allocate(a_self, a_newSize, a_alignment, a_alignmentRequired); else if (a_oldMem) { void *original_mem = (std::atomic *) (((uint64_t) a_oldMem) - 0x100); + + //logger::trace("MemoryManagerStats::Reallocate ptr {} (internal ptr {}) diff {}.", reinterpret_cast(a_oldMem), reinterpret_cast(original_mem), reinterpret_cast(a_oldMem) - reinterpret_cast(original_mem)); + std::atomic *original_cookie = (std::atomic *) (((uint64_t) a_oldMem) - 0x100); - uint64_t expected = 0x1337DEADDEAD1337; + uint64_t expected = 0x1337DEADDEAD1337; if (original_cookie->compare_exchange_strong(expected, (uint64_t) 0x1337DEADDEAD1337)) { void *new_mem = a_alignmentRequired ? scalable_aligned_realloc(original_mem, a_newSize + 0x100, a_alignment) : scalable_realloc(original_mem, a_newSize + 0x100); *(uint64_t *) new_mem = (uint64_t) 0x1337DEADDEAD1337; return (void *) (((uint64_t) new_mem) + 0x100); } + else + { + logger::warn("MemoryManager::Reallocate error 302: already deallocated for addr {}.", reinterpret_cast(a_oldMem)); + return g_trash; + } } + return g_trash; } void ReplaceAllocRoutines() { @@ -168,7 +182,9 @@ namespace { void* Allocate(RE::ScrapHeap*, std::size_t a_size, std::size_t a_alignment) { - return MemoryManager::Allocate(nullptr,a_size,a_alignment,true); + // TODO: std::size_t -> std::uint32_t + //logger::trace("ScrapHeap::Allocate a_size: {}; a_alignment: {}; static_cast a_alignment: {}.", a_size, a_alignment, static_cast(a_alignment)); + return MemoryManager::Allocate(nullptr, a_size, static_cast(a_alignment), true); } RE::ScrapHeap* Ctor(RE::ScrapHeap* a_this) @@ -180,6 +196,7 @@ namespace void Deallocate(RE::ScrapHeap*, void* a_mem) { + //logger::trace("ScrapHeap::Deallocate {}.", reinterpret_cast(a_mem)); return MemoryManager::Deallocate(nullptr,a_mem,true); }