Merge pull request #2281 from knewstimek/pr/windows-aligned-delete-fix

fix(windows): use matching deallocator for CRT aligned blocks
This commit is contained in:
Martin Vogel authored and GitHub committed 2026-10-25 19:09:31 +01:00
commit 023e997fd8
2 files changed
+37 -1

No files matched your search

+4 -1
View File
@@ -56,6 +56,7 @@ void *__real_malloc(size_t size);
void *__real_calloc(size_t count, size_t size);
void *__real_realloc(void *block, size_t size);
void __real_free(void *block);
void __real__aligned_free(void *block);
char *__real_strdup(const char *text);
size_t __real__msize(void *block);
/* Wrappers must call __real_* for anything that is itself wrapped: a plain
@@ -155,7 +156,9 @@ void __wrap__aligned_free(void *block) {
mi_free(block);
return;
}
__real_free(block);
/* A CRT aligned block has its own bookkeeping header. Plain free is not
* its matching deallocator. */
__real__aligned_free(block);
}
void *__wrap_realloc(void *block, size_t size) {
+33
View File
@@ -30,6 +30,7 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <errno.h>
#endif
/* ASan detection — mimalloc MI_OVERRIDE=0 under ASan, mi_process_info
@@ -353,6 +354,34 @@ TEST(mem_rss_reflects_external_resident_memory) {
PASS();
}
#ifdef _WIN32
/* A block the CRT's _aligned_malloc made starts past the CRT's bookkeeping
* header, so the aligned-free wrapper must return it through _aligned_free.
* Plain free receives an interior pointer: ASan reports a bad free, and the
* Windows heap either rejects the free (errno) or terminates the process.
* --wrap makes __real__aligned_malloc the CRT's own allocator, so the block is
* genuinely foreign to mimalloc. The wrapper is called by name: the routing
* inside it is what this pins, independent of which references the linker
* rewrites. */
void *__real__aligned_malloc(size_t size, size_t alignment);
void __wrap__aligned_free(void *block);
TEST(mem_win_aligned_free_returns_crt_block_to_crt) {
enum { CRT_BLOCK_SIZE = 256, CRT_BLOCK_ALIGNMENT = 64 };
unsigned char *block = __real__aligned_malloc(CRT_BLOCK_SIZE, CRT_BLOCK_ALIGNMENT);
ASSERT_NOT_NULL(block);
/* Without a CRT-owned block the wrapper takes its mimalloc path instead. */
ASSERT_FALSE(mi_is_in_heap_region(block));
ASSERT_EQ((uintptr_t)block % CRT_BLOCK_ALIGNMENT, 0);
memset(block, 0xA5, CRT_BLOCK_SIZE);
errno = 0;
__wrap__aligned_free(block);
ASSERT_EQ(errno, 0);
ASSERT_TRUE(HeapValidate(GetProcessHeap(), 0, NULL));
PASS();
}
#endif
TEST(mem_collect_rss_still_positive) {
cbm_mem_init(0.5);
cbm_mem_collect();
@@ -1745,6 +1774,10 @@ SUITE(mem) {
RUN_TEST(mem_rss_reflects_external_resident_memory);
RUN_TEST(mem_collect_no_crash);
RUN_TEST(mem_collect_rss_still_positive);
#ifdef _WIN32
/* Windows allocator wrappers */
RUN_TEST(mem_win_aligned_free_returns_crt_block_to_crt);
#endif
/* Memory pressure simulation */
RUN_TEST(mem_progressive_alloc_rss_increases);
RUN_TEST(mem_free_and_collect_no_crash);