extend interpose for macOSX

This commit is contained in:
daan 2020-02-02 19:07:26 -08:00
parent 12c4108abe
commit 757dcc8411
2 changed files with 21 additions and 20 deletions

View file

@ -269,11 +269,11 @@ static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* tot
/* ---------------------------------------------------------------------------------------- /* ----------------------------------------------------------------------------------------
The thread local default heap: `_mi_get_default_heap` return the thread local heap. The thread local default heap: `_mi_get_default_heap` return the thread local heap.
On most platforms (Windows, Linux, FreeBSD, NetBSD, etc), this just returns a On most platforms (Windows, Linux, FreeBSD, NetBSD, etc), this just returns a
__thread local variable (`_mi_heap_default`). With the initial-exec TLS model this ensures __thread local variable (`_mi_heap_default`). With the initial-exec TLS model this ensures
that the storage will always be available (allocated on the thread stacks). that the storage will always be available (allocated on the thread stacks).
On some platforms though we cannot use that when overriding `malloc` since the underlying On some platforms though we cannot use that when overriding `malloc` since the underlying
TLS implementation (or the loader) will call itself `malloc` on a first access and recurse. TLS implementation (or the loader) will call itself `malloc` on a first access and recurse.
We try to circumvent this in an efficient way: We try to circumvent this in an efficient way:
- macOSX : we use an unused TLS slot from the OS allocated slots (MI_TLS_SLOT). On OSX, the - macOSX : we use an unused TLS slot from the OS allocated slots (MI_TLS_SLOT). On OSX, the
loader itself calls `malloc` even before the modules are initialized. loader itself calls `malloc` even before the modules are initialized.
@ -285,11 +285,11 @@ extern const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value o
extern bool _mi_process_is_initialized; extern bool _mi_process_is_initialized;
mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap
#if defined(MI_MALLOC_OVERRIDE) #if defined(MI_MALLOC_OVERRIDE)
#if defined(__MACH__) // OSX #if defined(__MACH__) // OSX
#define MI_TLS_SLOT 89 // seems unused? (__PTK_FRAMEWORK_OLDGC_KEY9) see <https://github.com/rweichler/substrate/blob/master/include/pthread_machdep.h> #define MI_TLS_SLOT 84 // seems unused? (__PTK_FRAMEWORK_OLDGC_KEY9) see <https://github.com/rweichler/substrate/blob/master/include/pthread_machdep.h>
// possible unused ones are 9, 29, __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4 (94), __PTK_FRAMEWORK_GC_KEY9 (112) and __PTK_FRAMEWORK_OLDGC_KEY9 (89) // possible unused ones are 9, 29, __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4 (94), __PTK_FRAMEWORK_GC_KEY9 (112) and __PTK_FRAMEWORK_OLDGC_KEY9 (89)
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__)
#define MI_TLS_PTHREAD_SLOT_OFS (6*sizeof(int) + 1*sizeof(void*)) // offset `retval` <https://github.com/openbsd/src/blob/master/lib/libc/include/thread_private.h#L371> #define MI_TLS_PTHREAD_SLOT_OFS (6*sizeof(int) + 1*sizeof(void*)) // offset `retval` <https://github.com/openbsd/src/blob/master/lib/libc/include/thread_private.h#L371>
#elif defined(__DragonFly__) #elif defined(__DragonFly__)
#warning "mimalloc is not working correctly on DragonFly yet." #warning "mimalloc is not working correctly on DragonFly yet."
@ -299,7 +299,7 @@ mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing hea
#if defined(MI_TLS_SLOT) #if defined(MI_TLS_SLOT)
static inline void* mi_tls_slot(size_t slot); // forward declaration static inline void* mi_tls_slot(size_t slot); // forward declaration
#elif defined(MI_TLS_PTHREAD_SLOT_OFS) #elif defined(MI_TLS_PTHREAD_SLOT_OFS)
#include <pthread.h> #include <pthread.h>
static inline mi_heap_t** mi_tls_pthread_heap_slot(void) { static inline mi_heap_t** mi_tls_pthread_heap_slot(void) {
pthread_t self = pthread_self(); pthread_t self = pthread_self();
@ -308,7 +308,7 @@ static inline mi_heap_t** mi_tls_pthread_heap_slot(void) {
static mi_heap_t* pheap_main = _mi_heap_main_get(); static mi_heap_t* pheap_main = _mi_heap_main_get();
return &pheap_main; return &pheap_main;
} }
#endif #endif
return (mi_heap_t**)((uint8_t*)self + MI_TLS_PTHREAD_SLOT_OFS); return (mi_heap_t**)((uint8_t*)self + MI_TLS_PTHREAD_SLOT_OFS);
} }
#elif defined(MI_TLS_PTHREAD) #elif defined(MI_TLS_PTHREAD)
@ -319,7 +319,7 @@ extern mi_decl_thread mi_heap_t* _mi_heap_default; // default heap to allocate
#endif #endif
static inline mi_heap_t* mi_get_default_heap(void) { static inline mi_heap_t* mi_get_default_heap(void) {
#if defined(MI_TLS_SLOT) #if defined(MI_TLS_SLOT)
mi_heap_t* heap = (mi_heap_t*)mi_tls_slot(MI_TLS_SLOT); mi_heap_t* heap = (mi_heap_t*)mi_tls_slot(MI_TLS_SLOT);
return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap); return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap);
#elif defined(MI_TLS_PTHREAD_SLOT_OFS) #elif defined(MI_TLS_PTHREAD_SLOT_OFS)
@ -329,7 +329,7 @@ static inline mi_heap_t* mi_get_default_heap(void) {
mi_heap_t* heap = (mi_unlikely(_mi_heap_default_key == (pthread_key_t)(-1)) ? _mi_heap_main_get() : (mi_heap_t*)pthread_getspecific(_mi_heap_default_key)); mi_heap_t* heap = (mi_unlikely(_mi_heap_default_key == (pthread_key_t)(-1)) ? _mi_heap_main_get() : (mi_heap_t*)pthread_getspecific(_mi_heap_default_key));
return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap); return (mi_unlikely(heap == NULL) ? (mi_heap_t*)&_mi_heap_empty : heap);
#else #else
#if defined(MI_TLS_RECURSE_GUARD) #if defined(MI_TLS_RECURSE_GUARD)
if (mi_unlikely(!_mi_process_is_initialized)) return _mi_heap_main_get(); if (mi_unlikely(!_mi_process_is_initialized)) return _mi_heap_main_get();
#endif #endif
return _mi_heap_default; return _mi_heap_default;
@ -665,7 +665,7 @@ static inline size_t _mi_os_numa_node_count(void) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Getting the thread id should be performant as it is called in the // Getting the thread id should be performant as it is called in the
// fast path of `_mi_free` and we specialize for various platforms. // fast path of `_mi_free` and we specialize for various platforms.
// ------------------------------------------------------------------- // -------------------------------------------------------------------
#if defined(_WIN32) #if defined(_WIN32)

View file

@ -41,26 +41,27 @@ terms of the MIT license. A copy of the license can be found in the file
#endif #endif
#if defined(__APPLE__) && defined(MI_SHARED_LIB_EXPORT) && defined(MI_INTERPOSE) #if defined(__APPLE__) && defined(MI_SHARED_LIB_EXPORT) && defined(MI_INTERPOSE)
static void mi_free_tls_safe(void* p) {
if (mi_unlikely(_mi_preloading())) return;
mi_free(p);
}
// use interposing so `DYLD_INSERT_LIBRARIES` works without `DYLD_FORCE_FLAT_NAMESPACE=1` // use interposing so `DYLD_INSERT_LIBRARIES` works without `DYLD_FORCE_FLAT_NAMESPACE=1`
// See: <https://books.google.com/books?id=K8vUkpOXhN4C&pg=PA73> // See: <https://books.google.com/books?id=K8vUkpOXhN4C&pg=PA73>
struct mi_interpose_s { struct mi_interpose_s {
const void* replacement; const void* replacement;
const void* target; const void* target;
}; };
#define MI_INTERPOSEX(oldfun,newfun) { (const void*)&newfun, (const void*)&oldfun } #define MI_INTERPOSE_FUN(oldfun,newfun) { (const void*)&newfun, (const void*)&oldfun }
#define MI_INTERPOSE_MI(fun) MI_INTERPOSEX(fun,mi_##fun) #define MI_INTERPOSE_MI(fun) MI_INTERPOSE_FUN(fun,mi_##fun)
__attribute__((used)) static struct mi_interpose_s _mi_interposes[] __attribute__((section("__DATA, __interpose"))) = __attribute__((used)) static struct mi_interpose_s _mi_interposes[] __attribute__((section("__DATA, __interpose"))) =
{ {
MI_INTERPOSE_MI(malloc), MI_INTERPOSE_MI(malloc),
MI_INTERPOSE_MI(calloc), MI_INTERPOSE_MI(calloc),
MI_INTERPOSE_MI(realloc), MI_INTERPOSE_MI(realloc),
MI_INTERPOSEX(free,mi_free_tls_safe),
MI_INTERPOSE_MI(strdup), MI_INTERPOSE_MI(strdup),
MI_INTERPOSE_MI(strndup) MI_INTERPOSE_MI(strndup),
MI_INTERPOSE_MI(realpath),
MI_INTERPOSE_MI(posix_memalign),
MI_INTERPOSE_MI(reallocf),
MI_INTERPOSE_MI(valloc),
// some code allocates from a zone but deallocates using plain free :-( (like NxHashResizeToCapacity <https://github.com/nneonneo/osx-10.9-opensource/blob/master/objc4-551.1/runtime/hashtable2.mm>)
MI_INTERPOSE_FUN(free,mi_cfree), // use safe free that checks if pointers are from us
}; };
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
// cannot override malloc unless using a dll. // cannot override malloc unless using a dll.