1 | /* ---------------------------------------------------------------------------- |
2 | Copyright (c) 2018, Microsoft Research, Daan Leijen |
3 | This is free software; you can redistribute it and/or modify it under the |
4 | terms of the MIT license. A copy of the license can be found in the file |
5 | "LICENSE" at the root of this distribution. |
6 | -----------------------------------------------------------------------------*/ |
7 | |
8 | #if !defined(MI_IN_ALLOC_C) |
9 | #error "this file should be included from 'alloc.c' (so aliases can work)" |
10 | #endif |
11 | |
12 | #if defined(MI_MALLOC_OVERRIDE) && defined(_WIN32) && !(defined(MI_SHARED_LIB) && defined(_DLL)) |
13 | #error "It is only possible to override "malloc" on Windows when building as a DLL (and linking the C runtime as a DLL)" |
14 | #endif |
15 | |
16 | #if defined(MI_MALLOC_OVERRIDE) && !defined(_WIN32) |
17 | |
18 | // ------------------------------------------------------ |
19 | // Override system malloc |
20 | // ------------------------------------------------------ |
21 | |
22 | #if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__) |
23 | // use aliasing to alias the exported function to one of our `mi_` functions |
24 | #if (defined(__GNUC__) && __GNUC__ >= 9) |
25 | #define MI_FORWARD(fun) __attribute__((alias(#fun), used, visibility("default"), copy(fun))) |
26 | #else |
27 | #define MI_FORWARD(fun) __attribute__((alias(#fun), used, visibility("default"))) |
28 | #endif |
29 | #define MI_FORWARD1(fun,x) MI_FORWARD(fun) |
30 | #define MI_FORWARD2(fun,x,y) MI_FORWARD(fun) |
31 | #define MI_FORWARD3(fun,x,y,z) MI_FORWARD(fun) |
32 | #define MI_FORWARD0(fun,x) MI_FORWARD(fun) |
33 | #define MI_FORWARD02(fun,x,y) MI_FORWARD(fun) |
34 | #else |
35 | // use forwarding by calling our `mi_` function |
36 | #define MI_FORWARD1(fun,x) { return fun(x); } |
37 | #define MI_FORWARD2(fun,x,y) { return fun(x,y); } |
38 | #define MI_FORWARD3(fun,x,y,z) { return fun(x,y,z); } |
39 | #define MI_FORWARD0(fun,x) { fun(x); } |
40 | #define MI_FORWARD02(fun,x,y) { fun(x,y); } |
41 | #endif |
42 | |
43 | #if defined(__APPLE__) && defined(MI_SHARED_LIB_EXPORT) && defined(MI_INTERPOSE) |
44 | // use interposing so `DYLD_INSERT_LIBRARIES` works without `DYLD_FORCE_FLAT_NAMESPACE=1` |
45 | // See: <https://books.google.com/books?id=K8vUkpOXhN4C&pg=PA73> |
46 | struct mi_interpose_s { |
47 | const void* replacement; |
48 | const void* target; |
49 | }; |
50 | #define MI_INTERPOSEX(oldfun,newfun) { (const void*)&newfun, (const void*)&oldfun } |
51 | #define MI_INTERPOSE_MI(fun) MI_INTERPOSEX(fun,mi_##fun) |
52 | __attribute__((used)) static struct mi_interpose_s _mi_interposes[] __attribute__((section("__DATA, __interpose" ))) = |
53 | { |
54 | MI_INTERPOSE_MI(malloc), |
55 | MI_INTERPOSE_MI(calloc), |
56 | MI_INTERPOSE_MI(realloc), |
57 | MI_INTERPOSE_MI(free), |
58 | MI_INTERPOSE_MI(strdup), |
59 | MI_INTERPOSE_MI(strndup) |
60 | }; |
61 | #elif defined(_MSC_VER) |
62 | // cannot override malloc unless using a dll. |
63 | // we just override new/delete which does work in a static library. |
64 | #else |
65 | // On all other systems forward to our API |
66 | void* malloc(size_t size) mi_attr_noexcept MI_FORWARD1(mi_malloc, size); |
67 | void* calloc(size_t size, size_t n) mi_attr_noexcept MI_FORWARD2(mi_calloc, size, n); |
68 | void* realloc(void* p, size_t newsize) mi_attr_noexcept MI_FORWARD2(mi_realloc, p, newsize); |
69 | void free(void* p) mi_attr_noexcept MI_FORWARD0(mi_free, p); |
70 | #endif |
71 | |
72 | #if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__) |
73 | #pragma GCC visibility push(default) |
74 | #endif |
75 | |
76 | // ------------------------------------------------------ |
77 | // Override new/delete |
78 | // This is not really necessary as they usually call |
79 | // malloc/free anyway, but it improves performance. |
80 | // ------------------------------------------------------ |
81 | #ifdef __cplusplus |
82 | // ------------------------------------------------------ |
83 | // With a C++ compiler we override the new/delete operators. |
84 | // see <https://en.cppreference.com/w/cpp/memory/new/operator_new> |
85 | // ------------------------------------------------------ |
86 | #include <new> |
87 | void operator delete(void* p) noexcept MI_FORWARD0(mi_free,p); |
88 | void operator delete[](void* p) noexcept MI_FORWARD0(mi_free,p); |
89 | |
90 | void* operator new(std::size_t n) noexcept(false) MI_FORWARD1(mi_new,n); |
91 | void* operator new[](std::size_t n) noexcept(false) MI_FORWARD1(mi_new,n); |
92 | |
93 | void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { UNUSED(tag); return mi_new_nothrow(n); } |
94 | void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { UNUSED(tag); return mi_new_nothrow(n); } |
95 | |
96 | #if (__cplusplus >= 201402L || _MSC_VER >= 1916) |
97 | void operator delete (void* p, std::size_t n) MI_FORWARD02(mi_free_size,p,n); |
98 | void operator delete[](void* p, std::size_t n) MI_FORWARD02(mi_free_size,p,n); |
99 | #endif |
100 | |
101 | #if (__cplusplus > 201402L || defined(__cpp_aligned_new)) |
102 | void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); } |
103 | void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); } |
104 | 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)); }; |
105 | 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)); }; |
106 | |
107 | void* operator new( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); } |
108 | void* operator new[]( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); } |
109 | 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)); } |
110 | 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)); } |
111 | #endif |
112 | |
113 | #elif (defined(__GNUC__) || defined(__clang__)) |
114 | // ------------------------------------------------------ |
115 | // Override by defining the mangled C++ names of the operators (as |
116 | // used by GCC and CLang). |
117 | // See <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling> |
118 | // ------------------------------------------------------ |
119 | void _ZdlPv(void* p) MI_FORWARD0(mi_free,p); // delete |
120 | void _ZdaPv(void* p) MI_FORWARD0(mi_free,p); // delete[] |
121 | void _ZdlPvm(void* p, size_t n) MI_FORWARD02(mi_free_size,p,n); |
122 | void _ZdaPvm(void* p, size_t n) MI_FORWARD02(mi_free_size,p,n); |
123 | void _ZdlPvSt11align_val_t(void* p, size_t al) { mi_free_aligned(p,al); } |
124 | void _ZdaPvSt11align_val_t(void* p, size_t al) { mi_free_aligned(p,al); } |
125 | void _ZdlPvmSt11align_val_t(void* p, size_t n, size_t al) { mi_free_size_aligned(p,n,al); } |
126 | void _ZdaPvmSt11align_val_t(void* p, size_t n, size_t al) { mi_free_size_aligned(p,n,al); } |
127 | |
128 | typedef struct mi_nothrow_s { } mi_nothrow_t; |
129 | #if (MI_INTPTR_SIZE==8) |
130 | void* _Znwm(size_t n) MI_FORWARD1(mi_new,n); // new 64-bit |
131 | void* _Znam(size_t n) MI_FORWARD1(mi_new,n); // new[] 64-bit |
132 | void* _ZnwmSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al); |
133 | void* _ZnamSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al); |
134 | void* _ZnwmRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { UNUSED(tag); return mi_new_nothrow(n); } |
135 | void* _ZnamRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { UNUSED(tag); return mi_new_nothrow(n); } |
136 | void* _ZnwmSt11align_val_tRKSt9nothrow_t(size_t n, size_t al, mi_nothrow_t tag) { UNUSED(tag); return mi_new_aligned_nothrow(n,al); } |
137 | void* _ZnamSt11align_val_tRKSt9nothrow_t(size_t n, size_t al, mi_nothrow_t tag) { UNUSED(tag); return mi_new_aligned_nothrow(n,al); } |
138 | #elif (MI_INTPTR_SIZE==4) |
139 | void* _Znwj(size_t n) MI_FORWARD1(mi_new,n); // new 64-bit |
140 | void* _Znaj(size_t n) MI_FORWARD1(mi_new,n); // new[] 64-bit |
141 | void* _ZnwjSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al); |
142 | void* _ZnajSt11align_val_t(size_t n, size_t al) MI_FORWARD2(mi_new_aligned, n, al); |
143 | void* _ZnwjRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { UNUSED(tag); return mi_new_nothrow(n); } |
144 | void* _ZnajRKSt9nothrow_t(size_t n, mi_nothrow_t tag) { UNUSED(tag); return mi_new_nothrow(n); } |
145 | void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t n, size_t al, mi_nothrow_t tag) { UNUSED(tag); return mi_new_aligned_nothrow(n,al); } |
146 | void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t n, size_t al, mi_nothrow_t tag) { UNUSED(tag); return mi_new_aligned_nothrow(n,al); } |
147 | #else |
148 | #error "define overloads for new/delete for this platform (just for performance, can be skipped)" |
149 | #endif |
150 | #endif // __cplusplus |
151 | |
152 | |
153 | #ifdef __cplusplus |
154 | extern "C" { |
155 | #endif |
156 | |
157 | // ------------------------------------------------------ |
158 | // Posix & Unix functions definitions |
159 | // ------------------------------------------------------ |
160 | |
161 | void* reallocf(void* p, size_t newsize) MI_FORWARD2(mi_reallocf,p,newsize); |
162 | size_t malloc_size(void* p) MI_FORWARD1(mi_usable_size,p); |
163 | size_t malloc_usable_size(void *p) MI_FORWARD1(mi_usable_size,p); |
164 | void cfree(void* p) MI_FORWARD0(mi_free, p); |
165 | |
166 | // no forwarding here due to aliasing/name mangling issues |
167 | void* valloc(size_t size) { return mi_valloc(size); } |
168 | void* pvalloc(size_t size) { return mi_pvalloc(size); } |
169 | void* reallocarray(void* p, size_t count, size_t size) { return mi_reallocarray(p, count, size); } |
170 | void* memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); } |
171 | void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } |
172 | int posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p, alignment, size); } |
173 | |
174 | #if defined(__GLIBC__) && defined(__linux__) |
175 | // forward __libc interface (needed for glibc-based Linux distributions) |
176 | void* __libc_malloc(size_t size) MI_FORWARD1(mi_malloc,size); |
177 | void* __libc_calloc(size_t count, size_t size) MI_FORWARD2(mi_calloc,count,size); |
178 | void* __libc_realloc(void* p, size_t size) MI_FORWARD2(mi_realloc,p,size); |
179 | void __libc_free(void* p) MI_FORWARD0(mi_free,p); |
180 | void __libc_cfree(void* p) MI_FORWARD0(mi_free,p); |
181 | |
182 | void* __libc_valloc(size_t size) { return mi_valloc(size); } |
183 | void* __libc_pvalloc(size_t size) { return mi_pvalloc(size); } |
184 | void* __libc_memalign(size_t alignment, size_t size) { return mi_memalign(alignment,size); } |
185 | int __posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p,alignment,size); } |
186 | #endif |
187 | |
188 | #ifdef __cplusplus |
189 | } |
190 | #endif |
191 | |
192 | #if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__) |
193 | #pragma GCC visibility pop |
194 | #endif |
195 | |
196 | #endif // MI_MALLOC_OVERRIDE && !_WIN32 |
197 | |
198 | |