Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ if (MI_BUILD_TESTS)
enable_testing()

# static link tests
foreach(TEST_NAME api api-fill stress)
foreach(TEST_NAME api api-fill stress free-foreign)
add_executable(mimalloc-test-${TEST_NAME} test/test-${TEST_NAME}.c)
target_compile_definitions(mimalloc-test-${TEST_NAME} PRIVATE ${mi_defines})
target_compile_options(mimalloc-test-${TEST_NAME} PRIVATE ${mi_cflags})
Expand Down
4 changes: 0 additions & 4 deletions include/mimalloc/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,11 +657,7 @@ static inline mi_page_t* _mi_checked_ptr_page(const void* p) {

static inline mi_page_t* _mi_ptr_page(const void* p) {
mi_assert_internal(p==NULL || mi_is_in_heap_region(p));
#if MI_DEBUG || MI_SECURE || defined(__APPLE__)
return _mi_checked_ptr_page(p);
#else
return _mi_unchecked_ptr_page(p);
#endif
}


Expand Down
64 changes: 64 additions & 0 deletions test/test-free-foreign.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* ----------------------------------------------------------------------------
Copyright (c) 2018-2026, Microsoft Research, Daan Leijen
This is free software; you can redistribute it and/or modify it under the
terms of the MIT license. A copy of the license can be found in the file
"LICENSE" at the root of this distribution.
-----------------------------------------------------------------------------*/

/*
Regression test: `mi_free` must not crash when called on a pointer that was
not allocated by mimalloc. In LD_PRELOAD / override scenarios this is observed
in the wild when libraries with their own internal bookkeeping (e.g. LLVM via
Mesa's `gbm_create_device`) call `free()` on pointers that live on a thread
stack or on a static/TCB page whose pagemap submap entry is NULL.

Every other production allocator (glibc, jemalloc, tcmalloc) tolerates such
calls, and mimalloc's debug/MI_SECURE/macOS paths already did. This test
exercises the release-Linux fast path that historically bypassed the NULL
submap check in `_mi_ptr_page`.
*/

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "mimalloc.h"
#include "testhelper.h"

static uint8_t g_static_buffer[4096];

int main(void) {
mi_option_disable(mi_option_verbose);

CHECK_BODY("mi_free-NULL") {
mi_free(NULL);
result = true;
};

CHECK_BODY("mi_free-stack-pointer") {
uint8_t stack_buffer[256];
memset(stack_buffer, 0, sizeof(stack_buffer));
mi_free(&stack_buffer[16]);
result = true;
};

CHECK_BODY("mi_free-static-pointer") {
memset(g_static_buffer, 0, sizeof(g_static_buffer));
mi_free(&g_static_buffer[16]);
result = true;
};

CHECK_BODY("mi_free-mmap-style-pointer") {
uintptr_t fake = (uintptr_t)&g_static_buffer[0] ^ (uintptr_t)0x1000;
mi_free((void*)fake);
result = true;
};

CHECK_BODY("mi_free-roundtrip-after-foreign") {
void* p = mi_malloc(128);
result = (p != NULL);
if (result) { mi_free(p); }
};

return print_test_summary();
}