2019-06-20 02:26:12 +03:00
/* ----------------------------------------------------------------------------
2021-04-24 19:35:11 +03:00
Copyright ( c ) 2018 - 2021 , Microsoft Research , Daan Leijen
2019-06-20 02:26:12 +03:00
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
2019-06-23 14:53:34 +03:00
" LICENSE " at the root of this distribution .
2019-06-20 02:26:12 +03:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# if !defined(MI_IN_ALLOC_C)
# error "this file should be included from 'alloc.c' (so aliases can work)"
# endif
# if defined(MI_MALLOC_OVERRIDE) && defined(_WIN32) && !(defined(MI_SHARED_LIB) && defined(_DLL))
2019-09-02 20:18:34 +03:00
# error "It is only possible to override "malloc" on Windows when building as a DLL (and linking the C runtime as a DLL)"
2019-06-20 02:26:12 +03:00
# endif
2021-11-03 07:54:44 +03:00
# if defined(MI_MALLOC_OVERRIDE) && !(defined(_WIN32))
2019-06-20 02:26:12 +03:00
2021-11-05 04:55:12 +03:00
# if defined(__APPLE__)
mi_decl_externc void vfree ( void * p ) ;
mi_decl_externc size_t malloc_size ( const void * p ) ;
mi_decl_externc size_t malloc_good_size ( size_t size ) ;
# endif
// helper definition for C override of C++ new
typedef struct mi_nothrow_s { int _tag ; } mi_nothrow_t ;
2019-06-20 02:26:12 +03:00
// ------------------------------------------------------
// Override system malloc
// ------------------------------------------------------
2021-11-05 04:55:12 +03:00
# if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__) && !defined(MI_VALGRIND)
// gcc, clang: use aliasing to alias the exported function to one of our `mi_` functions
2019-07-09 01:45:37 +03:00
# if (defined(__GNUC__) && __GNUC__ >= 9)
2021-10-28 05:06:27 +03:00
# pragma GCC diagnostic ignored "-Wattributes" // or we get warnings that nodiscard is ignored on a forward
2021-06-18 05:15:09 +03:00
# define MI_FORWARD(fun) __attribute__((alias(#fun), used, visibility("default"), copy(fun)));
2019-07-09 01:45:37 +03:00
# else
2021-06-18 05:15:09 +03:00
# define MI_FORWARD(fun) __attribute__((alias(#fun), used, visibility("default")));
2019-07-09 01:45:37 +03:00
# endif
2019-07-07 23:44:33 +03:00
# define MI_FORWARD1(fun,x) MI_FORWARD(fun)
# define MI_FORWARD2(fun,x,y) MI_FORWARD(fun)
# define MI_FORWARD3(fun,x,y,z) MI_FORWARD(fun)
# define MI_FORWARD0(fun,x) MI_FORWARD(fun)
2019-07-08 04:11:21 +03:00
# define MI_FORWARD02(fun,x,y) MI_FORWARD(fun)
2019-06-20 02:26:12 +03:00
# else
2021-11-05 04:55:12 +03:00
// otherwise use forwarding by calling our `mi_` function
2019-07-07 23:44:33 +03:00
# define MI_FORWARD1(fun,x) { return fun(x); }
# define MI_FORWARD2(fun,x,y) { return fun(x,y); }
# define MI_FORWARD3(fun,x,y,z) { return fun(x,y,z); }
# define MI_FORWARD0(fun,x) { fun(x); }
2019-07-08 04:11:21 +03:00
# define MI_FORWARD02(fun,x,y) { fun(x,y); }
2019-06-20 02:26:12 +03:00
# endif
2021-11-05 04:55:12 +03:00
# if defined(__APPLE__) && defined(MI_SHARED_LIB_EXPORT) && defined(MI_OSX_INTERPOSE)
// define MI_OSX_IS_INTERPOSED as we should not provide forwarding definitions for
// functions that are interposed (or the interposing does not work)
# define MI_OSX_IS_INTERPOSED
2021-11-03 07:54:44 +03:00
2019-06-20 02:26:12 +03:00
// use interposing so `DYLD_INSERT_LIBRARIES` works without `DYLD_FORCE_FLAT_NAMESPACE=1`
// See: <https://books.google.com/books?id=K8vUkpOXhN4C&pg=PA73>
struct mi_interpose_s {
const void * replacement ;
const void * target ;
} ;
2020-02-03 06:07:26 +03:00
# define MI_INTERPOSE_FUN(oldfun,newfun) { (const void*)&newfun, (const void*)&oldfun }
# define MI_INTERPOSE_MI(fun) MI_INTERPOSE_FUN(fun,mi_##fun)
2021-11-03 07:54:44 +03:00
2019-06-20 02:26:12 +03:00
__attribute__ ( ( used ) ) static struct mi_interpose_s _mi_interposes [ ] __attribute__ ( ( section ( " __DATA, __interpose " ) ) ) =
{
MI_INTERPOSE_MI ( malloc ) ,
MI_INTERPOSE_MI ( calloc ) ,
MI_INTERPOSE_MI ( realloc ) ,
2019-07-02 22:49:28 +03:00
MI_INTERPOSE_MI ( strdup ) ,
2020-02-03 06:07:26 +03:00
MI_INTERPOSE_MI ( strndup ) ,
MI_INTERPOSE_MI ( realpath ) ,
MI_INTERPOSE_MI ( posix_memalign ) ,
MI_INTERPOSE_MI ( reallocf ) ,
MI_INTERPOSE_MI ( valloc ) ,
2021-11-03 07:54:44 +03:00
MI_INTERPOSE_MI ( malloc_size ) ,
MI_INTERPOSE_MI ( malloc_good_size ) ,
MI_INTERPOSE_MI ( aligned_alloc ) ,
2021-11-05 04:55:12 +03:00
# ifdef MI_OSX_ZONE
2021-11-03 07:54:44 +03:00
// we interpose malloc_default_zone in alloc-override-osx.c so we can use mi_free safely
2020-12-16 03:03:54 +03:00
MI_INTERPOSE_MI ( free ) ,
2021-11-03 07:54:44 +03:00
MI_INTERPOSE_FUN ( vfree , mi_free ) ,
2021-11-05 04:55:12 +03:00
# else
// sometimes code allocates from default zone but deallocates using plain free :-( (like NxHashResizeToCapacity <https://github.com/nneonneo/osx-10.9-opensource/blob/master/objc4-551.1/runtime/hashtable2.mm>)
2020-02-03 06:07:26 +03:00
MI_INTERPOSE_FUN ( free , mi_cfree ) , // use safe free that checks if pointers are from us
2021-11-05 04:55:12 +03:00
MI_INTERPOSE_FUN ( vfree , mi_cfree ) ,
2020-12-16 03:03:54 +03:00
# endif
2019-06-20 02:26:12 +03:00
} ;
2021-11-05 04:55:12 +03:00
# ifdef __cplusplus
extern " C " {
void _ZdlPv ( void * p ) ; // delete
void _ZdaPv ( void * p ) ; // delete[]
void _ZdlPvm ( void * p , size_t n ) ; // delete
void _ZdaPvm ( void * p , size_t n ) ; // delete[]
void * _Znwm ( size_t n ) ; // new
void * _Znam ( size_t n ) ; // new[]
void * _ZnwmRKSt9nothrow_t ( size_t n , mi_nothrow_t tag ) ; // new nothrow
void * _ZnamRKSt9nothrow_t ( size_t n , mi_nothrow_t tag ) ; // new[] nothrow
}
__attribute__ ( ( used ) ) static struct mi_interpose_s _mi_cxx_interposes [ ] __attribute__ ( ( section ( " __DATA, __interpose " ) ) ) =
{
MI_INTERPOSE_FUN ( _ZdlPv , mi_free ) ,
MI_INTERPOSE_FUN ( _ZdaPv , mi_free ) ,
MI_INTERPOSE_FUN ( _ZdlPvm , mi_free_size ) ,
MI_INTERPOSE_FUN ( _ZdaPvm , mi_free_size ) ,
MI_INTERPOSE_FUN ( _Znwm , mi_new ) ,
MI_INTERPOSE_FUN ( _Znam , mi_new ) ,
MI_INTERPOSE_FUN ( _ZnwmRKSt9nothrow_t , mi_new_nothrow ) ,
MI_INTERPOSE_FUN ( _ZnamRKSt9nothrow_t , mi_new_nothrow ) ,
} ;
# endif // __cplusplus
2019-07-19 05:52:29 +03:00
# elif defined(_MSC_VER)
// cannot override malloc unless using a dll.
// we just override new/delete which does work in a static library.
2019-06-20 02:26:12 +03:00
# else
2021-11-03 07:54:44 +03:00
// On all other systems forward to our API
2021-06-18 05:15:09 +03:00
void * malloc ( size_t size ) MI_FORWARD1 ( mi_malloc , size )
void * calloc ( size_t size , size_t n ) MI_FORWARD2 ( mi_calloc , size , n )
void * realloc ( void * p , size_t newsize ) MI_FORWARD2 ( mi_realloc , p , newsize )
void free ( void * p ) MI_FORWARD0 ( mi_free , p )
2019-06-20 02:26:12 +03:00
# endif
2021-04-18 20:02:13 +03:00
# if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__)
2019-06-23 18:04:43 +03:00
# pragma GCC visibility push(default)
# endif
2019-06-20 02:26:12 +03:00
// ------------------------------------------------------
// Override new/delete
// This is not really necessary as they usually call
// malloc/free anyway, but it improves performance.
// ------------------------------------------------------
# ifdef __cplusplus
// ------------------------------------------------------
// With a C++ compiler we override the new/delete operators.
// see <https://en.cppreference.com/w/cpp/memory/new/operator_new>
// ------------------------------------------------------
# include <new>
2021-11-05 04:55:12 +03:00
# ifndef MI_OSX_IS_INTERPOSED
void operator delete ( void * p ) noexcept MI_FORWARD0 ( mi_free , p )
void operator delete [ ] ( void * p ) noexcept MI_FORWARD0 ( mi_free , p )
2019-07-08 04:11:21 +03:00
2021-11-05 04:55:12 +03:00
void * operator new ( std : : size_t n ) noexcept ( false ) MI_FORWARD1 ( mi_new , n )
void * operator new [ ] ( std : : size_t n ) noexcept ( false ) MI_FORWARD1 ( mi_new , n )
2019-07-08 04:11:21 +03:00
2021-11-14 01:46:03 +03:00
void * operator new ( std : : size_t n , const std : : nothrow_t & tag ) noexcept { MI_UNUSED ( tag ) ; return mi_new_nothrow ( n ) ; }
void * operator new [ ] ( std : : size_t n , const std : : nothrow_t & tag ) noexcept { MI_UNUSED ( tag ) ; return mi_new_nothrow ( n ) ; }
2019-07-08 04:11:21 +03:00
2021-11-05 04:55:12 +03:00
# if (__cplusplus >= 201402L || _MSC_VER >= 1916)
void operator delete ( void * p , std : : size_t n ) noexcept MI_FORWARD02 ( mi_free_size , p , n )
void operator delete [ ] ( void * p , std : : size_t n ) noexcept MI_FORWARD02 ( mi_free_size , p , n )
# endif
2019-06-20 02:26:12 +03:00
# endif
2019-07-08 04:11:21 +03:00
2020-04-28 19:09:54 +03:00
# if (__cplusplus > 201402L && defined(__cpp_aligned_new)) && (!defined(__GNUC__) || (__GNUC__ > 5))
2019-07-08 04:11:21 +03:00
void operator delete ( void * p , std : : align_val_t al ) noexcept { mi_free_aligned ( p , static_cast < size_t > ( al ) ) ; }
void operator delete [ ] ( void * p , std : : align_val_t al ) noexcept { mi_free_aligned ( p , static_cast < size_t > ( al ) ) ; }
2019-07-15 05:56:33 +03:00
void operator delete ( void * p , std : : size_t n , std : : align_val_t al ) noexcept { mi_free_size_aligned ( p , n , static_cast < size_t > ( al ) ) ; } ;
void operator delete [ ] ( void * p , std : : size_t n , std : : align_val_t al ) noexcept { mi_free_size_aligned ( p , n , static_cast < size_t > ( al ) ) ; } ;
2019-07-08 04:11:21 +03:00
2019-07-15 05:56:33 +03:00
void * operator new ( std : : size_t n , std : : align_val_t al ) noexcept ( false ) { return mi_new_aligned ( n , static_cast < size_t > ( al ) ) ; }
void * operator new [ ] ( std : : size_t n , std : : align_val_t al ) noexcept ( false ) { return mi_new_aligned ( n , static_cast < size_t > ( al ) ) ; }
void * operator new ( std : : size_t n , std : : align_val_t al , const std : : nothrow_t & ) noexcept { return mi_new_aligned_nothrow ( n , static_cast < size_t > ( al ) ) ; }
void * operator new [ ] ( std : : size_t n , std : : align_val_t al , const std : : nothrow_t & ) noexcept { return mi_new_aligned_nothrow ( n , static_cast < size_t > ( al ) ) ; }
2019-06-20 02:26:12 +03:00
# endif
2019-07-08 04:11:21 +03:00
2021-11-05 04:55:12 +03:00
# elif (defined(__GNUC__) || defined(__clang__))
2019-07-08 04:11:21 +03:00
// ------------------------------------------------------
// Override by defining the mangled C++ names of the operators (as
2019-06-20 02:26:12 +03:00
// used by GCC and CLang).
// See <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling>
// ------------------------------------------------------
2021-11-05 04:55:12 +03:00
2021-06-18 05:15:09 +03:00
void _ZdlPv ( void * p ) MI_FORWARD0 ( mi_free , p ) // delete
void _ZdaPv ( void * p ) MI_FORWARD0 ( mi_free , p ) // delete[]
void _ZdlPvm ( void * p , size_t n ) MI_FORWARD02 ( mi_free_size , p , n )
void _ZdaPvm ( void * p , size_t n ) MI_FORWARD02 ( mi_free_size , p , n )
2019-07-15 05:56:33 +03:00
void _ZdlPvSt11align_val_t ( void * p , size_t al ) { mi_free_aligned ( p , al ) ; }
void _ZdaPvSt11align_val_t ( void * p , size_t al ) { mi_free_aligned ( p , al ) ; }
void _ZdlPvmSt11align_val_t ( void * p , size_t n , size_t al ) { mi_free_size_aligned ( p , n , al ) ; }
void _ZdaPvmSt11align_val_t ( void * p , size_t n , size_t al ) { mi_free_size_aligned ( p , n , al ) ; }
2021-11-05 04:55:12 +03:00
2019-06-20 02:26:12 +03:00
# if (MI_INTPTR_SIZE==8)
2021-06-18 05:15:09 +03:00
void * _Znwm ( size_t n ) MI_FORWARD1 ( mi_new , n ) // new 64-bit
void * _Znam ( size_t n ) MI_FORWARD1 ( mi_new , n ) // new[] 64-bit
2021-11-14 01:46:03 +03:00
void * _ZnwmRKSt9nothrow_t ( size_t n , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_nothrow ( n ) ; }
void * _ZnamRKSt9nothrow_t ( size_t n , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_nothrow ( n ) ; }
2021-06-18 05:15:09 +03:00
void * _ZnwmSt11align_val_t ( size_t n , size_t al ) MI_FORWARD2 ( mi_new_aligned , n , al )
void * _ZnamSt11align_val_t ( size_t n , size_t al ) MI_FORWARD2 ( mi_new_aligned , n , al )
2021-11-14 01:46:03 +03:00
void * _ZnwmSt11align_val_tRKSt9nothrow_t ( size_t n , size_t al , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_aligned_nothrow ( n , al ) ; }
void * _ZnamSt11align_val_tRKSt9nothrow_t ( size_t n , size_t al , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_aligned_nothrow ( n , al ) ; }
2019-06-20 02:26:12 +03:00
# elif (MI_INTPTR_SIZE==4)
2021-06-18 05:15:09 +03:00
void * _Znwj ( size_t n ) MI_FORWARD1 ( mi_new , n ) // new 64-bit
void * _Znaj ( size_t n ) MI_FORWARD1 ( mi_new , n ) // new[] 64-bit
2021-11-14 01:46:03 +03:00
void * _ZnwjRKSt9nothrow_t ( size_t n , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_nothrow ( n ) ; }
void * _ZnajRKSt9nothrow_t ( size_t n , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_nothrow ( n ) ; }
2021-06-18 05:15:09 +03:00
void * _ZnwjSt11align_val_t ( size_t n , size_t al ) MI_FORWARD2 ( mi_new_aligned , n , al )
void * _ZnajSt11align_val_t ( size_t n , size_t al ) MI_FORWARD2 ( mi_new_aligned , n , al )
2021-11-14 01:46:03 +03:00
void * _ZnwjSt11align_val_tRKSt9nothrow_t ( size_t n , size_t al , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_aligned_nothrow ( n , al ) ; }
void * _ZnajSt11align_val_tRKSt9nothrow_t ( size_t n , size_t al , mi_nothrow_t tag ) { MI_UNUSED ( tag ) ; return mi_new_aligned_nothrow ( n , al ) ; }
2019-06-20 02:26:12 +03:00
# else
2021-11-05 04:55:12 +03:00
# error "define overloads for new / delete for this platform (just for performance, can be skipped)"
2019-06-20 02:26:12 +03:00
# endif
# endif // __cplusplus
2021-11-05 04:55:12 +03:00
// ------------------------------------------------------
// Further Posix & Unix functions definitions
// ------------------------------------------------------
2019-06-20 02:26:12 +03:00
# ifdef __cplusplus
extern " C " {
# endif
2021-11-05 04:55:12 +03:00
# ifndef MI_OSX_IS_INTERPOSED
// Forward Posix/Unix calls as well
void * reallocf ( void * p , size_t newsize ) MI_FORWARD2 ( mi_reallocf , p , newsize )
size_t malloc_size ( const void * p ) MI_FORWARD1 ( mi_usable_size , p )
# if !defined(__ANDROID__) && !defined(__FreeBSD__)
size_t malloc_usable_size ( void * p ) MI_FORWARD1 ( mi_usable_size , p )
# else
size_t malloc_usable_size ( const void * p ) MI_FORWARD1 ( mi_usable_size , p )
# endif
2019-06-20 02:26:12 +03:00
2021-11-05 04:55:12 +03:00
// No forwarding here due to aliasing/name mangling issues
2021-11-05 05:10:15 +03:00
void * valloc ( size_t size ) { return mi_valloc ( size ) ; }
void vfree ( void * p ) { mi_free ( p ) ; }
size_t malloc_good_size ( size_t size ) { return mi_malloc_good_size ( size ) ; }
int posix_memalign ( void * * p , size_t alignment , size_t size ) { return mi_posix_memalign ( p , alignment , size ) ; }
2021-11-05 04:55:12 +03:00
// `aligned_alloc` is only available when __USE_ISOC11 is defined.
// Note: Conda has a custom glibc where `aligned_alloc` is declared `static inline` and we cannot
// override it, but both _ISOC11_SOURCE and __USE_ISOC11 are undefined in Conda GCC7 or GCC9.
// Fortunately, in the case where `aligned_alloc` is declared as `static inline` it
// uses internally `memalign`, `posix_memalign`, or `_aligned_malloc` so we can avoid overriding it ourselves.
# if __USE_ISOC11
void * aligned_alloc ( size_t alignment , size_t size ) { return mi_aligned_alloc ( alignment , size ) ; }
# endif
2020-04-14 16:20:56 +03:00
# endif
2019-06-20 02:26:12 +03:00
2019-07-07 23:44:33 +03:00
// no forwarding here due to aliasing/name mangling issues
2021-11-05 05:10:15 +03:00
void cfree ( void * p ) { mi_free ( p ) ; }
void * pvalloc ( size_t size ) { return mi_pvalloc ( size ) ; }
void * reallocarray ( void * p , size_t count , size_t size ) { return mi_reallocarray ( p , count , size ) ; }
2021-12-16 03:33:49 +03:00
int reallocarr ( void * p , size_t count , size_t size ) { return mi_reallocarr ( p , count , size ) ; }
2021-11-05 05:10:15 +03:00
void * memalign ( size_t alignment , size_t size ) { return mi_memalign ( alignment , size ) ; }
void * _aligned_malloc ( size_t alignment , size_t size ) { return mi_aligned_alloc ( alignment , size ) ; }
2020-04-20 19:27:43 +03:00
2019-06-20 02:26:12 +03:00
# if defined(__GLIBC__) && defined(__linux__)
2019-06-29 20:17:13 +03:00
// forward __libc interface (needed for glibc-based Linux distributions)
2021-11-05 05:10:15 +03:00
void * __libc_malloc ( size_t size ) MI_FORWARD1 ( mi_malloc , size )
void * __libc_calloc ( size_t count , size_t size ) MI_FORWARD2 ( mi_calloc , count , size )
void * __libc_realloc ( void * p , size_t size ) MI_FORWARD2 ( mi_realloc , p , size )
void __libc_free ( void * p ) MI_FORWARD0 ( mi_free , p )
void __libc_cfree ( void * p ) MI_FORWARD0 ( mi_free , p )
2019-06-20 02:26:12 +03:00
2021-11-05 05:10:15 +03:00
void * __libc_valloc ( size_t size ) { return mi_valloc ( size ) ; }
void * __libc_pvalloc ( size_t size ) { return mi_pvalloc ( size ) ; }
void * __libc_memalign ( size_t alignment , size_t size ) { return mi_memalign ( alignment , size ) ; }
2020-04-20 19:27:43 +03:00
int __posix_memalign ( void * * p , size_t alignment , size_t size ) { return mi_posix_memalign ( p , alignment , size ) ; }
2019-06-20 02:26:12 +03:00
# endif
# ifdef __cplusplus
}
# endif
2021-04-18 20:02:13 +03:00
# if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__)
2019-06-23 18:04:43 +03:00
# pragma GCC visibility pop
# endif
2019-07-19 04:59:32 +03:00
# endif // MI_MALLOC_OVERRIDE && !_WIN32