xref: /oneTBB/src/tbbmalloc_proxy/proxy.cpp (revision 51c0b2f7)
1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2005-2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev #if __linux__ && !__ANDROID__
18*51c0b2f7Stbbdev // include <bits/c++config.h> indirectly so that <cstdlib> is not included
19*51c0b2f7Stbbdev #include <cstddef>
20*51c0b2f7Stbbdev // include <features.h> indirectly so that <stdlib.h> is not included
21*51c0b2f7Stbbdev #include <unistd.h>
22*51c0b2f7Stbbdev // Working around compiler issue with Anaconda's gcc 7.3 compiler package.
23*51c0b2f7Stbbdev // New gcc ported for old libc may provide their inline implementation
24*51c0b2f7Stbbdev // of aligned_alloc as required by new C++ standard, this makes it hard to
25*51c0b2f7Stbbdev // redefine aligned_alloc here. However, running on systems with new libc
26*51c0b2f7Stbbdev // version, it still needs it to be redefined, thus tricking system headers
27*51c0b2f7Stbbdev #if defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 16) && _GLIBCXX_HAVE_ALIGNED_ALLOC
28*51c0b2f7Stbbdev // tell <cstdlib> that there is no aligned_alloc
29*51c0b2f7Stbbdev #undef _GLIBCXX_HAVE_ALIGNED_ALLOC
30*51c0b2f7Stbbdev // trick <stdlib.h> to define another symbol instead
31*51c0b2f7Stbbdev #define aligned_alloc __hidden_redefined_aligned_alloc
32*51c0b2f7Stbbdev // Fix the state and undefine the trick
33*51c0b2f7Stbbdev #include <cstdlib>
34*51c0b2f7Stbbdev #undef aligned_alloc
35*51c0b2f7Stbbdev #endif // defined(__GLIBC_PREREQ)&&!__GLIBC_PREREQ(2, 16)&&_GLIBCXX_HAVE_ALIGNED_ALLOC
36*51c0b2f7Stbbdev #endif // __linux__ && !__ANDROID__
37*51c0b2f7Stbbdev 
38*51c0b2f7Stbbdev #include "proxy.h"
39*51c0b2f7Stbbdev 
40*51c0b2f7Stbbdev #include "tbb/detail/_config.h"
41*51c0b2f7Stbbdev #include "../tbb/environment.h"
42*51c0b2f7Stbbdev 
43*51c0b2f7Stbbdev #if !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) && !defined(__SUNPRO_CC)
44*51c0b2f7Stbbdev     #if TBB_USE_EXCEPTIONS
45*51c0b2f7Stbbdev         #error Compilation settings do not support exception handling. Please do not set TBB_USE_EXCEPTIONS macro or set it to 0.
46*51c0b2f7Stbbdev     #elif !defined(TBB_USE_EXCEPTIONS)
47*51c0b2f7Stbbdev         #define TBB_USE_EXCEPTIONS 0
48*51c0b2f7Stbbdev     #endif
49*51c0b2f7Stbbdev #elif !defined(TBB_USE_EXCEPTIONS)
50*51c0b2f7Stbbdev     #define TBB_USE_EXCEPTIONS 1
51*51c0b2f7Stbbdev #endif
52*51c0b2f7Stbbdev 
53*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || _WIN32 && !__TBB_WIN8UI_SUPPORT
54*51c0b2f7Stbbdev /*** internal global operator new implementation (Linux, Windows) ***/
55*51c0b2f7Stbbdev #include <new>
56*51c0b2f7Stbbdev 
57*51c0b2f7Stbbdev // Synchronization primitives to protect original library pointers and new_handler
58*51c0b2f7Stbbdev #include "../tbbmalloc/Synchronize.h"
59*51c0b2f7Stbbdev // Use MallocMutex implementation
60*51c0b2f7Stbbdev typedef MallocMutex ProxyMutex;
61*51c0b2f7Stbbdev 
62*51c0b2f7Stbbdev // In case there is no std::get_new_handler function
63*51c0b2f7Stbbdev // which provides synchronized access to std::new_handler
64*51c0b2f7Stbbdev #if !__TBB_CPP11_GET_NEW_HANDLER_PRESENT
65*51c0b2f7Stbbdev static ProxyMutex new_lock;
66*51c0b2f7Stbbdev #endif
67*51c0b2f7Stbbdev 
68*51c0b2f7Stbbdev static inline void* InternalOperatorNew(size_t sz) {
69*51c0b2f7Stbbdev     void* res = scalable_malloc(sz);
70*51c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
71*51c0b2f7Stbbdev     while (!res) {
72*51c0b2f7Stbbdev         std::new_handler handler;
73*51c0b2f7Stbbdev #if __TBB_CPP11_GET_NEW_HANDLER_PRESENT
74*51c0b2f7Stbbdev         handler = std::get_new_handler();
75*51c0b2f7Stbbdev #else
76*51c0b2f7Stbbdev         {
77*51c0b2f7Stbbdev             ProxyMutex::scoped_lock lock(new_lock);
78*51c0b2f7Stbbdev             handler = std::set_new_handler(0);
79*51c0b2f7Stbbdev             std::set_new_handler(handler);
80*51c0b2f7Stbbdev         }
81*51c0b2f7Stbbdev #endif
82*51c0b2f7Stbbdev         if (handler) {
83*51c0b2f7Stbbdev             (*handler)();
84*51c0b2f7Stbbdev         } else {
85*51c0b2f7Stbbdev             throw std::bad_alloc();
86*51c0b2f7Stbbdev         }
87*51c0b2f7Stbbdev         res = scalable_malloc(sz);
88*51c0b2f7Stbbdev }
89*51c0b2f7Stbbdev #endif /* TBB_USE_EXCEPTIONS */
90*51c0b2f7Stbbdev     return res;
91*51c0b2f7Stbbdev }
92*51c0b2f7Stbbdev /*** end of internal global operator new implementation ***/
93*51c0b2f7Stbbdev #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || _WIN32 && !__TBB_WIN8UI_SUPPORT
94*51c0b2f7Stbbdev 
95*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
96*51c0b2f7Stbbdev 
97*51c0b2f7Stbbdev #ifndef __THROW
98*51c0b2f7Stbbdev #define __THROW
99*51c0b2f7Stbbdev #endif
100*51c0b2f7Stbbdev 
101*51c0b2f7Stbbdev /*** service functions and variables ***/
102*51c0b2f7Stbbdev #include <string.h> // for memset
103*51c0b2f7Stbbdev #include <unistd.h> // for sysconf
104*51c0b2f7Stbbdev 
105*51c0b2f7Stbbdev static long memoryPageSize;
106*51c0b2f7Stbbdev 
107*51c0b2f7Stbbdev static inline void initPageSize()
108*51c0b2f7Stbbdev {
109*51c0b2f7Stbbdev     memoryPageSize = sysconf(_SC_PAGESIZE);
110*51c0b2f7Stbbdev }
111*51c0b2f7Stbbdev 
112*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED
113*51c0b2f7Stbbdev #include <dlfcn.h>
114*51c0b2f7Stbbdev #include <malloc.h>    // mallinfo
115*51c0b2f7Stbbdev 
116*51c0b2f7Stbbdev /* __TBB_malloc_proxy used as a weak symbol by libtbbmalloc for:
117*51c0b2f7Stbbdev    1) detection that the proxy library is loaded
118*51c0b2f7Stbbdev    2) check that dlsym("malloc") found something different from our replacement malloc
119*51c0b2f7Stbbdev */
120*51c0b2f7Stbbdev 
121*51c0b2f7Stbbdev // Starting from GCC 9, the -Wmissing-attributes warning was extended for alias below
122*51c0b2f7Stbbdev #if __GNUC__ >= 9
123*51c0b2f7Stbbdev     #pragma GCC diagnostic push
124*51c0b2f7Stbbdev     #pragma GCC diagnostic ignored "-Wmissing-attributes"
125*51c0b2f7Stbbdev #endif
126*51c0b2f7Stbbdev extern "C" void *__TBB_malloc_proxy(size_t) __attribute__ ((alias ("malloc")));
127*51c0b2f7Stbbdev #if __GNUC__ == 9
128*51c0b2f7Stbbdev     #pragma GCC diagnostic pop
129*51c0b2f7Stbbdev #endif
130*51c0b2f7Stbbdev 
131*51c0b2f7Stbbdev static void *orig_msize;
132*51c0b2f7Stbbdev 
133*51c0b2f7Stbbdev #elif MALLOC_ZONE_OVERLOAD_ENABLED
134*51c0b2f7Stbbdev 
135*51c0b2f7Stbbdev #include "proxy_overload_osx.h"
136*51c0b2f7Stbbdev 
137*51c0b2f7Stbbdev #endif // MALLOC_ZONE_OVERLOAD_ENABLED
138*51c0b2f7Stbbdev 
139*51c0b2f7Stbbdev // Original (i.e., replaced) functions,
140*51c0b2f7Stbbdev // they are never changed for MALLOC_ZONE_OVERLOAD_ENABLED.
141*51c0b2f7Stbbdev static void *orig_free,
142*51c0b2f7Stbbdev     *orig_realloc;
143*51c0b2f7Stbbdev 
144*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED
145*51c0b2f7Stbbdev #define ZONE_ARG
146*51c0b2f7Stbbdev #define PREFIX(name) name
147*51c0b2f7Stbbdev 
148*51c0b2f7Stbbdev static void *orig_libc_free,
149*51c0b2f7Stbbdev     *orig_libc_realloc;
150*51c0b2f7Stbbdev 
151*51c0b2f7Stbbdev // We already tried to find ptr to original functions.
152*51c0b2f7Stbbdev static std::atomic<bool> origFuncSearched{false};
153*51c0b2f7Stbbdev 
154*51c0b2f7Stbbdev inline void InitOrigPointers()
155*51c0b2f7Stbbdev {
156*51c0b2f7Stbbdev     // race is OK here, as different threads found same functions
157*51c0b2f7Stbbdev     if (!origFuncSearched.load(std::memory_order_acquire)) {
158*51c0b2f7Stbbdev         orig_free = dlsym(RTLD_NEXT, "free");
159*51c0b2f7Stbbdev         orig_realloc = dlsym(RTLD_NEXT, "realloc");
160*51c0b2f7Stbbdev         orig_msize = dlsym(RTLD_NEXT, "malloc_usable_size");
161*51c0b2f7Stbbdev         orig_libc_free = dlsym(RTLD_NEXT, "__libc_free");
162*51c0b2f7Stbbdev         orig_libc_realloc = dlsym(RTLD_NEXT, "__libc_realloc");
163*51c0b2f7Stbbdev 
164*51c0b2f7Stbbdev         origFuncSearched.store(true, std::memory_order_release);
165*51c0b2f7Stbbdev     }
166*51c0b2f7Stbbdev }
167*51c0b2f7Stbbdev 
168*51c0b2f7Stbbdev /*** replacements for malloc and the family ***/
169*51c0b2f7Stbbdev extern "C" {
170*51c0b2f7Stbbdev #elif MALLOC_ZONE_OVERLOAD_ENABLED
171*51c0b2f7Stbbdev 
172*51c0b2f7Stbbdev // each impl_* function has such 1st argument, it's unused
173*51c0b2f7Stbbdev #define ZONE_ARG struct _malloc_zone_t *,
174*51c0b2f7Stbbdev #define PREFIX(name) impl_##name
175*51c0b2f7Stbbdev // not interested in original functions for zone overload
176*51c0b2f7Stbbdev inline void InitOrigPointers() {}
177*51c0b2f7Stbbdev 
178*51c0b2f7Stbbdev #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED and MALLOC_ZONE_OVERLOAD_ENABLED
179*51c0b2f7Stbbdev 
180*51c0b2f7Stbbdev void *PREFIX(malloc)(ZONE_ARG size_t size) __THROW
181*51c0b2f7Stbbdev {
182*51c0b2f7Stbbdev     return scalable_malloc(size);
183*51c0b2f7Stbbdev }
184*51c0b2f7Stbbdev 
185*51c0b2f7Stbbdev void *PREFIX(calloc)(ZONE_ARG size_t num, size_t size) __THROW
186*51c0b2f7Stbbdev {
187*51c0b2f7Stbbdev     return scalable_calloc(num, size);
188*51c0b2f7Stbbdev }
189*51c0b2f7Stbbdev 
190*51c0b2f7Stbbdev void PREFIX(free)(ZONE_ARG void *object) __THROW
191*51c0b2f7Stbbdev {
192*51c0b2f7Stbbdev     InitOrigPointers();
193*51c0b2f7Stbbdev     __TBB_malloc_safer_free(object, (void (*)(void*))orig_free);
194*51c0b2f7Stbbdev }
195*51c0b2f7Stbbdev 
196*51c0b2f7Stbbdev void *PREFIX(realloc)(ZONE_ARG void* ptr, size_t sz) __THROW
197*51c0b2f7Stbbdev {
198*51c0b2f7Stbbdev     InitOrigPointers();
199*51c0b2f7Stbbdev     return __TBB_malloc_safer_realloc(ptr, sz, orig_realloc);
200*51c0b2f7Stbbdev }
201*51c0b2f7Stbbdev 
202*51c0b2f7Stbbdev /* The older *NIX interface for aligned allocations;
203*51c0b2f7Stbbdev    it's formally substituted by posix_memalign and deprecated,
204*51c0b2f7Stbbdev    so we do not expect it to cause cyclic dependency with C RTL. */
205*51c0b2f7Stbbdev void *PREFIX(memalign)(ZONE_ARG size_t alignment, size_t size) __THROW
206*51c0b2f7Stbbdev {
207*51c0b2f7Stbbdev     return scalable_aligned_malloc(size, alignment);
208*51c0b2f7Stbbdev }
209*51c0b2f7Stbbdev 
210*51c0b2f7Stbbdev /* valloc allocates memory aligned on a page boundary */
211*51c0b2f7Stbbdev void *PREFIX(valloc)(ZONE_ARG size_t size) __THROW
212*51c0b2f7Stbbdev {
213*51c0b2f7Stbbdev     if (! memoryPageSize) initPageSize();
214*51c0b2f7Stbbdev 
215*51c0b2f7Stbbdev     return scalable_aligned_malloc(size, memoryPageSize);
216*51c0b2f7Stbbdev }
217*51c0b2f7Stbbdev 
218*51c0b2f7Stbbdev #undef ZONE_ARG
219*51c0b2f7Stbbdev #undef PREFIX
220*51c0b2f7Stbbdev 
221*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED
222*51c0b2f7Stbbdev 
223*51c0b2f7Stbbdev // match prototype from system headers
224*51c0b2f7Stbbdev #if __ANDROID__
225*51c0b2f7Stbbdev size_t malloc_usable_size(const void *ptr) __THROW
226*51c0b2f7Stbbdev #else
227*51c0b2f7Stbbdev size_t malloc_usable_size(void *ptr) __THROW
228*51c0b2f7Stbbdev #endif
229*51c0b2f7Stbbdev {
230*51c0b2f7Stbbdev     InitOrigPointers();
231*51c0b2f7Stbbdev     return __TBB_malloc_safer_msize(const_cast<void*>(ptr), (size_t (*)(void*))orig_msize);
232*51c0b2f7Stbbdev }
233*51c0b2f7Stbbdev 
234*51c0b2f7Stbbdev int posix_memalign(void **memptr, size_t alignment, size_t size) __THROW
235*51c0b2f7Stbbdev {
236*51c0b2f7Stbbdev     return scalable_posix_memalign(memptr, alignment, size);
237*51c0b2f7Stbbdev }
238*51c0b2f7Stbbdev 
239*51c0b2f7Stbbdev /* pvalloc allocates smallest set of complete pages which can hold
240*51c0b2f7Stbbdev    the requested number of bytes. Result is aligned on page boundary. */
241*51c0b2f7Stbbdev void *pvalloc(size_t size) __THROW
242*51c0b2f7Stbbdev {
243*51c0b2f7Stbbdev     if (! memoryPageSize) initPageSize();
244*51c0b2f7Stbbdev     // align size up to the page size,
245*51c0b2f7Stbbdev     // pvalloc(0) returns 1 page, see man libmpatrol
246*51c0b2f7Stbbdev     size = size? ((size-1) | (memoryPageSize-1)) + 1 : memoryPageSize;
247*51c0b2f7Stbbdev 
248*51c0b2f7Stbbdev     return scalable_aligned_malloc(size, memoryPageSize);
249*51c0b2f7Stbbdev }
250*51c0b2f7Stbbdev 
251*51c0b2f7Stbbdev int mallopt(int /*param*/, int /*value*/) __THROW
252*51c0b2f7Stbbdev {
253*51c0b2f7Stbbdev     return 1;
254*51c0b2f7Stbbdev }
255*51c0b2f7Stbbdev 
256*51c0b2f7Stbbdev struct mallinfo mallinfo() __THROW
257*51c0b2f7Stbbdev {
258*51c0b2f7Stbbdev     struct mallinfo m;
259*51c0b2f7Stbbdev     memset(&m, 0, sizeof(struct mallinfo));
260*51c0b2f7Stbbdev 
261*51c0b2f7Stbbdev     return m;
262*51c0b2f7Stbbdev }
263*51c0b2f7Stbbdev 
264*51c0b2f7Stbbdev #if __ANDROID__
265*51c0b2f7Stbbdev // Android doesn't have malloc_usable_size, provide it to be compatible
266*51c0b2f7Stbbdev // with Linux, in addition overload dlmalloc_usable_size() that presented
267*51c0b2f7Stbbdev // under Android.
268*51c0b2f7Stbbdev size_t dlmalloc_usable_size(const void *ptr) __attribute__ ((alias ("malloc_usable_size")));
269*51c0b2f7Stbbdev #else // __ANDROID__
270*51c0b2f7Stbbdev // C11 function, supported starting GLIBC 2.16
271*51c0b2f7Stbbdev void *aligned_alloc(size_t alignment, size_t size) __attribute__ ((alias ("memalign")));
272*51c0b2f7Stbbdev // Those non-standard functions are exported by GLIBC, and might be used
273*51c0b2f7Stbbdev // in conjunction with standard malloc/free, so we must ovberload them.
274*51c0b2f7Stbbdev // Bionic doesn't have them. Not removing from the linker scripts,
275*51c0b2f7Stbbdev // as absent entry points are ignored by the linker.
276*51c0b2f7Stbbdev 
277*51c0b2f7Stbbdev // Starting from GCC 9, the -Wmissing-attributes warning was extended for aliases below
278*51c0b2f7Stbbdev #if __GNUC__ >= 9
279*51c0b2f7Stbbdev     #pragma GCC diagnostic push
280*51c0b2f7Stbbdev     #pragma GCC diagnostic ignored "-Wmissing-attributes"
281*51c0b2f7Stbbdev #endif
282*51c0b2f7Stbbdev void *__libc_malloc(size_t size) __attribute__ ((alias ("malloc")));
283*51c0b2f7Stbbdev void *__libc_calloc(size_t num, size_t size) __attribute__ ((alias ("calloc")));
284*51c0b2f7Stbbdev void *__libc_memalign(size_t alignment, size_t size) __attribute__ ((alias ("memalign")));
285*51c0b2f7Stbbdev void *__libc_pvalloc(size_t size) __attribute__ ((alias ("pvalloc")));
286*51c0b2f7Stbbdev void *__libc_valloc(size_t size) __attribute__ ((alias ("valloc")));
287*51c0b2f7Stbbdev #if __GNUC__ == 9
288*51c0b2f7Stbbdev     #pragma GCC diagnostic pop
289*51c0b2f7Stbbdev #endif
290*51c0b2f7Stbbdev 
291*51c0b2f7Stbbdev // call original __libc_* to support naive replacement of free via __libc_free etc
292*51c0b2f7Stbbdev void __libc_free(void *ptr)
293*51c0b2f7Stbbdev {
294*51c0b2f7Stbbdev     InitOrigPointers();
295*51c0b2f7Stbbdev     __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_libc_free);
296*51c0b2f7Stbbdev }
297*51c0b2f7Stbbdev 
298*51c0b2f7Stbbdev void *__libc_realloc(void *ptr, size_t size)
299*51c0b2f7Stbbdev {
300*51c0b2f7Stbbdev     InitOrigPointers();
301*51c0b2f7Stbbdev     return __TBB_malloc_safer_realloc(ptr, size, orig_libc_realloc);
302*51c0b2f7Stbbdev }
303*51c0b2f7Stbbdev #endif // !__ANDROID__
304*51c0b2f7Stbbdev 
305*51c0b2f7Stbbdev } /* extern "C" */
306*51c0b2f7Stbbdev 
307*51c0b2f7Stbbdev /*** replacements for global operators new and delete ***/
308*51c0b2f7Stbbdev 
309*51c0b2f7Stbbdev void* operator new(size_t sz) {
310*51c0b2f7Stbbdev     return InternalOperatorNew(sz);
311*51c0b2f7Stbbdev }
312*51c0b2f7Stbbdev void* operator new[](size_t sz) {
313*51c0b2f7Stbbdev     return InternalOperatorNew(sz);
314*51c0b2f7Stbbdev }
315*51c0b2f7Stbbdev void operator delete(void* ptr) noexcept {
316*51c0b2f7Stbbdev     InitOrigPointers();
317*51c0b2f7Stbbdev     __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free);
318*51c0b2f7Stbbdev }
319*51c0b2f7Stbbdev void operator delete[](void* ptr) noexcept {
320*51c0b2f7Stbbdev     InitOrigPointers();
321*51c0b2f7Stbbdev     __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free);
322*51c0b2f7Stbbdev }
323*51c0b2f7Stbbdev void* operator new(size_t sz, const std::nothrow_t&) noexcept {
324*51c0b2f7Stbbdev     return scalable_malloc(sz);
325*51c0b2f7Stbbdev }
326*51c0b2f7Stbbdev void* operator new[](std::size_t sz, const std::nothrow_t&) noexcept {
327*51c0b2f7Stbbdev     return scalable_malloc(sz);
328*51c0b2f7Stbbdev }
329*51c0b2f7Stbbdev void operator delete(void* ptr, const std::nothrow_t&) noexcept {
330*51c0b2f7Stbbdev     InitOrigPointers();
331*51c0b2f7Stbbdev     __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free);
332*51c0b2f7Stbbdev }
333*51c0b2f7Stbbdev void operator delete[](void* ptr, const std::nothrow_t&) noexcept {
334*51c0b2f7Stbbdev     InitOrigPointers();
335*51c0b2f7Stbbdev     __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free);
336*51c0b2f7Stbbdev }
337*51c0b2f7Stbbdev 
338*51c0b2f7Stbbdev #endif /* MALLOC_UNIXLIKE_OVERLOAD_ENABLED */
339*51c0b2f7Stbbdev #endif /* MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED */
340*51c0b2f7Stbbdev 
341*51c0b2f7Stbbdev #ifdef _WIN32
342*51c0b2f7Stbbdev #include <windows.h>
343*51c0b2f7Stbbdev 
344*51c0b2f7Stbbdev #if !__TBB_WIN8UI_SUPPORT
345*51c0b2f7Stbbdev 
346*51c0b2f7Stbbdev #include <stdio.h>
347*51c0b2f7Stbbdev 
348*51c0b2f7Stbbdev #include "function_replacement.h"
349*51c0b2f7Stbbdev 
350*51c0b2f7Stbbdev template<typename T, size_t N> // generic function to find length of array
351*51c0b2f7Stbbdev inline size_t arrayLength(const T(&)[N]) {
352*51c0b2f7Stbbdev     return N;
353*51c0b2f7Stbbdev }
354*51c0b2f7Stbbdev 
355*51c0b2f7Stbbdev void __TBB_malloc_safer_delete( void *ptr)
356*51c0b2f7Stbbdev {
357*51c0b2f7Stbbdev     __TBB_malloc_safer_free( ptr, NULL );
358*51c0b2f7Stbbdev }
359*51c0b2f7Stbbdev 
360*51c0b2f7Stbbdev void* safer_aligned_malloc( size_t size, size_t alignment )
361*51c0b2f7Stbbdev {
362*51c0b2f7Stbbdev     // workaround for "is power of 2 pow N" bug that accepts zeros
363*51c0b2f7Stbbdev     return scalable_aligned_malloc( size, alignment>sizeof(size_t*)?alignment:sizeof(size_t*) );
364*51c0b2f7Stbbdev }
365*51c0b2f7Stbbdev 
366*51c0b2f7Stbbdev // we do not support _expand();
367*51c0b2f7Stbbdev void* safer_expand( void *, size_t )
368*51c0b2f7Stbbdev {
369*51c0b2f7Stbbdev     return NULL;
370*51c0b2f7Stbbdev }
371*51c0b2f7Stbbdev 
372*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(CRTLIB)                                             \
373*51c0b2f7Stbbdev void (*orig_free_##CRTLIB)(void*);                                                                   \
374*51c0b2f7Stbbdev void __TBB_malloc_safer_free_##CRTLIB(void *ptr)                                                     \
375*51c0b2f7Stbbdev {                                                                                                    \
376*51c0b2f7Stbbdev     __TBB_malloc_safer_free( ptr, orig_free_##CRTLIB );                                              \
377*51c0b2f7Stbbdev }                                                                                                    \
378*51c0b2f7Stbbdev                                                                                                      \
379*51c0b2f7Stbbdev void (*orig__aligned_free_##CRTLIB)(void*);                                                          \
380*51c0b2f7Stbbdev void __TBB_malloc_safer__aligned_free_##CRTLIB(void *ptr)                                            \
381*51c0b2f7Stbbdev {                                                                                                    \
382*51c0b2f7Stbbdev     __TBB_malloc_safer_free( ptr, orig__aligned_free_##CRTLIB );                                     \
383*51c0b2f7Stbbdev }                                                                                                    \
384*51c0b2f7Stbbdev                                                                                                      \
385*51c0b2f7Stbbdev size_t (*orig__msize_##CRTLIB)(void*);                                                               \
386*51c0b2f7Stbbdev size_t __TBB_malloc_safer__msize_##CRTLIB(void *ptr)                                                 \
387*51c0b2f7Stbbdev {                                                                                                    \
388*51c0b2f7Stbbdev     return __TBB_malloc_safer_msize( ptr, orig__msize_##CRTLIB );                                    \
389*51c0b2f7Stbbdev }                                                                                                    \
390*51c0b2f7Stbbdev                                                                                                      \
391*51c0b2f7Stbbdev size_t (*orig__aligned_msize_##CRTLIB)(void*, size_t, size_t);                                       \
392*51c0b2f7Stbbdev size_t __TBB_malloc_safer__aligned_msize_##CRTLIB( void *ptr, size_t alignment, size_t offset)       \
393*51c0b2f7Stbbdev {                                                                                                    \
394*51c0b2f7Stbbdev     return __TBB_malloc_safer_aligned_msize( ptr, alignment, offset, orig__aligned_msize_##CRTLIB ); \
395*51c0b2f7Stbbdev }                                                                                                    \
396*51c0b2f7Stbbdev                                                                                                      \
397*51c0b2f7Stbbdev void* __TBB_malloc_safer_realloc_##CRTLIB( void *ptr, size_t size )                                  \
398*51c0b2f7Stbbdev {                                                                                                    \
399*51c0b2f7Stbbdev     orig_ptrs func_ptrs = {orig_free_##CRTLIB, orig__msize_##CRTLIB};                                \
400*51c0b2f7Stbbdev     return __TBB_malloc_safer_realloc( ptr, size, &func_ptrs );                                      \
401*51c0b2f7Stbbdev }                                                                                                    \
402*51c0b2f7Stbbdev                                                                                                      \
403*51c0b2f7Stbbdev void* __TBB_malloc_safer__aligned_realloc_##CRTLIB( void *ptr, size_t size, size_t alignment )       \
404*51c0b2f7Stbbdev {                                                                                                    \
405*51c0b2f7Stbbdev     orig_aligned_ptrs func_ptrs = {orig__aligned_free_##CRTLIB, orig__aligned_msize_##CRTLIB};       \
406*51c0b2f7Stbbdev     return __TBB_malloc_safer_aligned_realloc( ptr, size, alignment, &func_ptrs );                   \
407*51c0b2f7Stbbdev }
408*51c0b2f7Stbbdev 
409*51c0b2f7Stbbdev // Only for ucrtbase: substitution for _o_free
410*51c0b2f7Stbbdev void (*orig__o_free)(void*);
411*51c0b2f7Stbbdev void __TBB_malloc__o_free(void *ptr)
412*51c0b2f7Stbbdev {
413*51c0b2f7Stbbdev     __TBB_malloc_safer_free( ptr, orig__o_free );
414*51c0b2f7Stbbdev }
415*51c0b2f7Stbbdev // Only for ucrtbase: substitution for _free_base
416*51c0b2f7Stbbdev void(*orig__free_base)(void*);
417*51c0b2f7Stbbdev void __TBB_malloc__free_base(void *ptr)
418*51c0b2f7Stbbdev {
419*51c0b2f7Stbbdev     __TBB_malloc_safer_free(ptr, orig__free_base);
420*51c0b2f7Stbbdev }
421*51c0b2f7Stbbdev 
422*51c0b2f7Stbbdev // Size limit is MAX_PATTERN_SIZE (28) byte codes / 56 symbols per line.
423*51c0b2f7Stbbdev // * can be used to match any digit in byte codes.
424*51c0b2f7Stbbdev // # followed by several * indicate a relative address that needs to be corrected.
425*51c0b2f7Stbbdev // Purpose of the pattern is to mark an instruction bound; it should consist of several
426*51c0b2f7Stbbdev // full instructions plus one extra byte code. It's not required for the patterns
427*51c0b2f7Stbbdev // to be unique (i.e., it's OK to have same pattern for unrelated functions).
428*51c0b2f7Stbbdev // TODO: use hot patch prologues if exist
429*51c0b2f7Stbbdev const char* known_bytecodes[] = {
430*51c0b2f7Stbbdev #if _WIN64
431*51c0b2f7Stbbdev //  "========================================================" - 56 symbols
432*51c0b2f7Stbbdev     "4883EC284885C974",       // release free()
433*51c0b2f7Stbbdev     "4883EC284885C975",       // release _msize()
434*51c0b2f7Stbbdev     "4885C974375348",         // release free() 8.0.50727.42, 10.0
435*51c0b2f7Stbbdev     "E907000000CCCC",         // release _aligned_msize(), _aligned_free() ucrtbase.dll
436*51c0b2f7Stbbdev     "C7442410000000008B",     // release free() ucrtbase.dll 10.0.14393.33
437*51c0b2f7Stbbdev     "E90B000000CCCC",         // release _msize() ucrtbase.dll 10.0.14393.33
438*51c0b2f7Stbbdev     "48895C24085748",         // release _aligned_msize() ucrtbase.dll 10.0.14393.33
439*51c0b2f7Stbbdev     "E903000000CCCC",         // release _aligned_msize() ucrtbase.dll 10.0.16299.522
440*51c0b2f7Stbbdev     "48894C24084883EC28BA",   // debug prologue
441*51c0b2f7Stbbdev     "4C894424184889542410",   // debug _aligned_msize() 10.0
442*51c0b2f7Stbbdev     "48894C24084883EC2848",   // debug _aligned_free 10.0
443*51c0b2f7Stbbdev     "488BD1488D0D#*******E9", // _o_free(), ucrtbase.dll
444*51c0b2f7Stbbdev  #if __TBB_OVERLOAD_OLD_MSVCR
445*51c0b2f7Stbbdev     "48895C2408574883EC3049", // release _aligned_msize 9.0
446*51c0b2f7Stbbdev     "4883EC384885C975",       // release _msize() 9.0
447*51c0b2f7Stbbdev     "4C8BC1488B0DA6E4040033", // an old win64 SDK
448*51c0b2f7Stbbdev  #endif
449*51c0b2f7Stbbdev #else // _WIN32
450*51c0b2f7Stbbdev //  "========================================================" - 56 symbols
451*51c0b2f7Stbbdev     "8BFF558BEC8B",           // multiple
452*51c0b2f7Stbbdev     "8BFF558BEC83",           // release free() & _msize() 10.0.40219.325, _msize() ucrtbase.dll
453*51c0b2f7Stbbdev     "8BFF558BECFF",           // release _aligned_msize ucrtbase.dll
454*51c0b2f7Stbbdev     "8BFF558BEC51",           // release free() & _msize() ucrtbase.dll 10.0.14393.33
455*51c0b2f7Stbbdev     "558BEC8B450885C074",     // release _aligned_free 11.0
456*51c0b2f7Stbbdev     "558BEC837D08000F",       // release _msize() 11.0.51106.1
457*51c0b2f7Stbbdev     "558BEC837D08007419FF",   // release free() 11.0.50727.1
458*51c0b2f7Stbbdev     "558BEC8B450885C075",     // release _aligned_msize() 11.0.50727.1
459*51c0b2f7Stbbdev     "558BEC6A018B",           // debug free() & _msize() 11.0
460*51c0b2f7Stbbdev     "558BEC8B451050",         // debug _aligned_msize() 11.0
461*51c0b2f7Stbbdev     "558BEC8B450850",         // debug _aligned_free 11.0
462*51c0b2f7Stbbdev     "8BFF558BEC6A",           // debug free() & _msize() 10.0.40219.325
463*51c0b2f7Stbbdev  #if __TBB_OVERLOAD_OLD_MSVCR
464*51c0b2f7Stbbdev     "6A1868********E8",       // release free() 8.0.50727.4053, 9.0
465*51c0b2f7Stbbdev     "6A1C68********E8",       // release _msize() 8.0.50727.4053, 9.0
466*51c0b2f7Stbbdev  #endif
467*51c0b2f7Stbbdev #endif // _WIN64/_WIN32
468*51c0b2f7Stbbdev     NULL
469*51c0b2f7Stbbdev     };
470*51c0b2f7Stbbdev 
471*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,function_name,dbgsuffix) \
472*51c0b2f7Stbbdev     ReplaceFunctionWithStore( #CRT_VER #dbgsuffix ".dll", #function_name, \
473*51c0b2f7Stbbdev       (FUNCPTR)__TBB_malloc_safer_##function_name##_##CRT_VER##dbgsuffix, \
474*51c0b2f7Stbbdev       known_bytecodes, (FUNCPTR*)&orig_##function_name##_##CRT_VER##dbgsuffix );
475*51c0b2f7Stbbdev 
476*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_NO_FALLBACK(CRT_VER,function_name,dbgsuffix) \
477*51c0b2f7Stbbdev     ReplaceFunctionWithStore( #CRT_VER #dbgsuffix ".dll", #function_name, \
478*51c0b2f7Stbbdev       (FUNCPTR)__TBB_malloc_safer_##function_name##_##CRT_VER##dbgsuffix, 0, NULL );
479*51c0b2f7Stbbdev 
480*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_REDIRECT(CRT_VER,function_name,dest_func,dbgsuffix) \
481*51c0b2f7Stbbdev     ReplaceFunctionWithStore( #CRT_VER #dbgsuffix ".dll", #function_name, \
482*51c0b2f7Stbbdev       (FUNCPTR)__TBB_malloc_safer_##dest_func##_##CRT_VER##dbgsuffix, 0, NULL );
483*51c0b2f7Stbbdev 
484*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_IMPL(CRT_VER,dbgsuffix)                             \
485*51c0b2f7Stbbdev     if (BytecodesAreKnown(#CRT_VER #dbgsuffix ".dll")) {                                          \
486*51c0b2f7Stbbdev       __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,free,dbgsuffix)                         \
487*51c0b2f7Stbbdev       __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,_msize,dbgsuffix)                       \
488*51c0b2f7Stbbdev       __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_NO_FALLBACK(CRT_VER,realloc,dbgsuffix)          \
489*51c0b2f7Stbbdev       __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,_aligned_free,dbgsuffix)                \
490*51c0b2f7Stbbdev       __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,_aligned_msize,dbgsuffix)               \
491*51c0b2f7Stbbdev       __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_NO_FALLBACK(CRT_VER,_aligned_realloc,dbgsuffix) \
492*51c0b2f7Stbbdev     } else                                                                                        \
493*51c0b2f7Stbbdev         SkipReplacement(#CRT_VER #dbgsuffix ".dll");
494*51c0b2f7Stbbdev 
495*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_RELEASE(CRT_VER) __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_IMPL(CRT_VER,)
496*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_DEBUG(CRT_VER) __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_IMPL(CRT_VER,d)
497*51c0b2f7Stbbdev 
498*51c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(CRT_VER)     \
499*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_RELEASE(CRT_VER) \
500*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_DEBUG(CRT_VER)
501*51c0b2f7Stbbdev 
502*51c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR
503*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr70d);
504*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr70);
505*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr71d);
506*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr71);
507*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr80d);
508*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr80);
509*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr90d);
510*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr90);
511*51c0b2f7Stbbdev #endif
512*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr100d);
513*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr100);
514*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr110d);
515*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr110);
516*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr120d);
517*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr120);
518*51c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(ucrtbase);
519*51c0b2f7Stbbdev 
520*51c0b2f7Stbbdev /*** replacements for global operators new and delete ***/
521*51c0b2f7Stbbdev 
522*51c0b2f7Stbbdev #if _MSC_VER && !defined(__INTEL_COMPILER)
523*51c0b2f7Stbbdev #pragma warning( push )
524*51c0b2f7Stbbdev #pragma warning( disable : 4290 )
525*51c0b2f7Stbbdev #endif
526*51c0b2f7Stbbdev 
527*51c0b2f7Stbbdev /*** operator new overloads internals (Linux, Windows) ***/
528*51c0b2f7Stbbdev 
529*51c0b2f7Stbbdev void* operator_new(size_t sz) {
530*51c0b2f7Stbbdev     return InternalOperatorNew(sz);
531*51c0b2f7Stbbdev }
532*51c0b2f7Stbbdev void* operator_new_arr(size_t sz) {
533*51c0b2f7Stbbdev     return InternalOperatorNew(sz);
534*51c0b2f7Stbbdev }
535*51c0b2f7Stbbdev void operator_delete(void* ptr) noexcept {
536*51c0b2f7Stbbdev     __TBB_malloc_safer_delete(ptr);
537*51c0b2f7Stbbdev }
538*51c0b2f7Stbbdev #if _MSC_VER && !defined(__INTEL_COMPILER)
539*51c0b2f7Stbbdev #pragma warning( pop )
540*51c0b2f7Stbbdev #endif
541*51c0b2f7Stbbdev 
542*51c0b2f7Stbbdev void operator_delete_arr(void* ptr) noexcept {
543*51c0b2f7Stbbdev     __TBB_malloc_safer_delete(ptr);
544*51c0b2f7Stbbdev }
545*51c0b2f7Stbbdev void* operator_new_t(size_t sz, const std::nothrow_t&) noexcept {
546*51c0b2f7Stbbdev     return scalable_malloc(sz);
547*51c0b2f7Stbbdev }
548*51c0b2f7Stbbdev void* operator_new_arr_t(std::size_t sz, const std::nothrow_t&) noexcept {
549*51c0b2f7Stbbdev     return scalable_malloc(sz);
550*51c0b2f7Stbbdev }
551*51c0b2f7Stbbdev void operator_delete_t(void* ptr, const std::nothrow_t&) noexcept {
552*51c0b2f7Stbbdev     __TBB_malloc_safer_delete(ptr);
553*51c0b2f7Stbbdev }
554*51c0b2f7Stbbdev void operator_delete_arr_t(void* ptr, const std::nothrow_t&) noexcept {
555*51c0b2f7Stbbdev     __TBB_malloc_safer_delete(ptr);
556*51c0b2f7Stbbdev }
557*51c0b2f7Stbbdev 
558*51c0b2f7Stbbdev struct Module {
559*51c0b2f7Stbbdev     const char *name;
560*51c0b2f7Stbbdev     bool        doFuncReplacement; // do replacement in the DLL
561*51c0b2f7Stbbdev };
562*51c0b2f7Stbbdev 
563*51c0b2f7Stbbdev Module modules_to_replace[] = {
564*51c0b2f7Stbbdev     {"msvcr100d.dll", true},
565*51c0b2f7Stbbdev     {"msvcr100.dll", true},
566*51c0b2f7Stbbdev     {"msvcr110d.dll", true},
567*51c0b2f7Stbbdev     {"msvcr110.dll", true},
568*51c0b2f7Stbbdev     {"msvcr120d.dll", true},
569*51c0b2f7Stbbdev     {"msvcr120.dll", true},
570*51c0b2f7Stbbdev     {"ucrtbase.dll", true},
571*51c0b2f7Stbbdev //    "ucrtbased.dll" is not supported because of problems with _dbg functions
572*51c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR
573*51c0b2f7Stbbdev     {"msvcr90d.dll", true},
574*51c0b2f7Stbbdev     {"msvcr90.dll", true},
575*51c0b2f7Stbbdev     {"msvcr80d.dll", true},
576*51c0b2f7Stbbdev     {"msvcr80.dll", true},
577*51c0b2f7Stbbdev     {"msvcr70d.dll", true},
578*51c0b2f7Stbbdev     {"msvcr70.dll", true},
579*51c0b2f7Stbbdev     {"msvcr71d.dll", true},
580*51c0b2f7Stbbdev     {"msvcr71.dll", true},
581*51c0b2f7Stbbdev #endif
582*51c0b2f7Stbbdev #if __TBB_TODO
583*51c0b2f7Stbbdev     // TODO: Try enabling replacement for non-versioned system binaries below
584*51c0b2f7Stbbdev     {"msvcrtd.dll", true},
585*51c0b2f7Stbbdev     {"msvcrt.dll", true},
586*51c0b2f7Stbbdev #endif
587*51c0b2f7Stbbdev     };
588*51c0b2f7Stbbdev 
589*51c0b2f7Stbbdev /*
590*51c0b2f7Stbbdev We need to replace following functions:
591*51c0b2f7Stbbdev malloc
592*51c0b2f7Stbbdev calloc
593*51c0b2f7Stbbdev _aligned_malloc
594*51c0b2f7Stbbdev _expand (by dummy implementation)
595*51c0b2f7Stbbdev ??2@YAPAXI@Z      operator new                         (ia32)
596*51c0b2f7Stbbdev ??_U@YAPAXI@Z     void * operator new[] (size_t size)  (ia32)
597*51c0b2f7Stbbdev ??3@YAXPAX@Z      operator delete                      (ia32)
598*51c0b2f7Stbbdev ??_V@YAXPAX@Z     operator delete[]                    (ia32)
599*51c0b2f7Stbbdev ??2@YAPEAX_K@Z    void * operator new(unsigned __int64)   (intel64)
600*51c0b2f7Stbbdev ??_V@YAXPEAX@Z    void * operator new[](unsigned __int64) (intel64)
601*51c0b2f7Stbbdev ??3@YAXPEAX@Z     operator delete                         (intel64)
602*51c0b2f7Stbbdev ??_V@YAXPEAX@Z    operator delete[]                       (intel64)
603*51c0b2f7Stbbdev ??2@YAPAXIABUnothrow_t@std@@@Z      void * operator new (size_t sz, const std::nothrow_t&) throw()  (optional)
604*51c0b2f7Stbbdev ??_U@YAPAXIABUnothrow_t@std@@@Z     void * operator new[] (size_t sz, const std::nothrow_t&) throw() (optional)
605*51c0b2f7Stbbdev 
606*51c0b2f7Stbbdev and these functions have runtime-specific replacement:
607*51c0b2f7Stbbdev realloc
608*51c0b2f7Stbbdev free
609*51c0b2f7Stbbdev _msize
610*51c0b2f7Stbbdev _aligned_realloc
611*51c0b2f7Stbbdev _aligned_free
612*51c0b2f7Stbbdev _aligned_msize
613*51c0b2f7Stbbdev */
614*51c0b2f7Stbbdev 
615*51c0b2f7Stbbdev typedef struct FRData_t {
616*51c0b2f7Stbbdev     //char *_module;
617*51c0b2f7Stbbdev     const char *_func;
618*51c0b2f7Stbbdev     FUNCPTR _fptr;
619*51c0b2f7Stbbdev     FRR_ON_ERROR _on_error;
620*51c0b2f7Stbbdev } FRDATA;
621*51c0b2f7Stbbdev 
622*51c0b2f7Stbbdev FRDATA c_routines_to_replace[] = {
623*51c0b2f7Stbbdev     { "malloc",  (FUNCPTR)scalable_malloc, FRR_FAIL },
624*51c0b2f7Stbbdev     { "calloc",  (FUNCPTR)scalable_calloc, FRR_FAIL },
625*51c0b2f7Stbbdev     { "_aligned_malloc",  (FUNCPTR)safer_aligned_malloc, FRR_FAIL },
626*51c0b2f7Stbbdev     { "_expand",  (FUNCPTR)safer_expand, FRR_IGNORE },
627*51c0b2f7Stbbdev };
628*51c0b2f7Stbbdev 
629*51c0b2f7Stbbdev FRDATA cxx_routines_to_replace[] = {
630*51c0b2f7Stbbdev #if _WIN64
631*51c0b2f7Stbbdev     { "??2@YAPEAX_K@Z", (FUNCPTR)operator_new, FRR_FAIL },
632*51c0b2f7Stbbdev     { "??_U@YAPEAX_K@Z", (FUNCPTR)operator_new_arr, FRR_FAIL },
633*51c0b2f7Stbbdev     { "??3@YAXPEAX@Z", (FUNCPTR)operator_delete, FRR_FAIL },
634*51c0b2f7Stbbdev     { "??_V@YAXPEAX@Z", (FUNCPTR)operator_delete_arr, FRR_FAIL },
635*51c0b2f7Stbbdev #else
636*51c0b2f7Stbbdev     { "??2@YAPAXI@Z", (FUNCPTR)operator_new, FRR_FAIL },
637*51c0b2f7Stbbdev     { "??_U@YAPAXI@Z", (FUNCPTR)operator_new_arr, FRR_FAIL },
638*51c0b2f7Stbbdev     { "??3@YAXPAX@Z", (FUNCPTR)operator_delete, FRR_FAIL },
639*51c0b2f7Stbbdev     { "??_V@YAXPAX@Z", (FUNCPTR)operator_delete_arr, FRR_FAIL },
640*51c0b2f7Stbbdev #endif
641*51c0b2f7Stbbdev     { "??2@YAPAXIABUnothrow_t@std@@@Z", (FUNCPTR)operator_new_t, FRR_IGNORE },
642*51c0b2f7Stbbdev     { "??_U@YAPAXIABUnothrow_t@std@@@Z", (FUNCPTR)operator_new_arr_t, FRR_IGNORE }
643*51c0b2f7Stbbdev };
644*51c0b2f7Stbbdev 
645*51c0b2f7Stbbdev #ifndef UNICODE
646*51c0b2f7Stbbdev typedef char unicode_char_t;
647*51c0b2f7Stbbdev #define WCHAR_SPEC "%s"
648*51c0b2f7Stbbdev #else
649*51c0b2f7Stbbdev typedef wchar_t unicode_char_t;
650*51c0b2f7Stbbdev #define WCHAR_SPEC "%ls"
651*51c0b2f7Stbbdev #endif
652*51c0b2f7Stbbdev 
653*51c0b2f7Stbbdev // Check that we recognize bytecodes that should be replaced by trampolines.
654*51c0b2f7Stbbdev // If some functions have unknown prologue patterns, replacement should not be done.
655*51c0b2f7Stbbdev bool BytecodesAreKnown(const unicode_char_t *dllName)
656*51c0b2f7Stbbdev {
657*51c0b2f7Stbbdev     const char *funcName[] = {"free", "_msize", "_aligned_free", "_aligned_msize", 0};
658*51c0b2f7Stbbdev     HMODULE module = GetModuleHandle(dllName);
659*51c0b2f7Stbbdev 
660*51c0b2f7Stbbdev     if (!module)
661*51c0b2f7Stbbdev         return false;
662*51c0b2f7Stbbdev     for (int i=0; funcName[i]; i++)
663*51c0b2f7Stbbdev         if (! IsPrologueKnown(dllName, funcName[i], known_bytecodes, module)) {
664*51c0b2f7Stbbdev             fprintf(stderr, "TBBmalloc: skip allocation functions replacement in " WCHAR_SPEC
665*51c0b2f7Stbbdev                     ": unknown prologue for function " WCHAR_SPEC "\n", dllName, funcName[i]);
666*51c0b2f7Stbbdev             return false;
667*51c0b2f7Stbbdev         }
668*51c0b2f7Stbbdev     return true;
669*51c0b2f7Stbbdev }
670*51c0b2f7Stbbdev 
671*51c0b2f7Stbbdev void SkipReplacement(const unicode_char_t *dllName)
672*51c0b2f7Stbbdev {
673*51c0b2f7Stbbdev #ifndef UNICODE
674*51c0b2f7Stbbdev     const char *dllStr = dllName;
675*51c0b2f7Stbbdev #else
676*51c0b2f7Stbbdev     const size_t sz = 128; // all DLL name must fit
677*51c0b2f7Stbbdev 
678*51c0b2f7Stbbdev     char buffer[sz];
679*51c0b2f7Stbbdev     size_t real_sz;
680*51c0b2f7Stbbdev     char *dllStr = buffer;
681*51c0b2f7Stbbdev 
682*51c0b2f7Stbbdev     errno_t ret = wcstombs_s(&real_sz, dllStr, sz, dllName, sz-1);
683*51c0b2f7Stbbdev     __TBB_ASSERT(!ret, "Dll name conversion failed");
684*51c0b2f7Stbbdev #endif
685*51c0b2f7Stbbdev 
686*51c0b2f7Stbbdev     for (size_t i=0; i<arrayLength(modules_to_replace); i++)
687*51c0b2f7Stbbdev         if (!strcmp(modules_to_replace[i].name, dllStr)) {
688*51c0b2f7Stbbdev             modules_to_replace[i].doFuncReplacement = false;
689*51c0b2f7Stbbdev             break;
690*51c0b2f7Stbbdev         }
691*51c0b2f7Stbbdev }
692*51c0b2f7Stbbdev 
693*51c0b2f7Stbbdev void ReplaceFunctionWithStore( const unicode_char_t *dllName, const char *funcName, FUNCPTR newFunc, const char ** opcodes, FUNCPTR* origFunc,  FRR_ON_ERROR on_error = FRR_FAIL )
694*51c0b2f7Stbbdev {
695*51c0b2f7Stbbdev     FRR_TYPE res = ReplaceFunction( dllName, funcName, newFunc, opcodes, origFunc );
696*51c0b2f7Stbbdev 
697*51c0b2f7Stbbdev     if (res == FRR_OK || res == FRR_NODLL || (res == FRR_NOFUNC && on_error == FRR_IGNORE))
698*51c0b2f7Stbbdev         return;
699*51c0b2f7Stbbdev 
700*51c0b2f7Stbbdev     fprintf(stderr, "Failed to %s function %s in module %s\n",
701*51c0b2f7Stbbdev             res==FRR_NOFUNC? "find" : "replace", funcName, dllName);
702*51c0b2f7Stbbdev 
703*51c0b2f7Stbbdev     // Unable to replace a required function
704*51c0b2f7Stbbdev     // Aborting because incomplete replacement of memory management functions
705*51c0b2f7Stbbdev     // may leave the program in an invalid state
706*51c0b2f7Stbbdev     abort();
707*51c0b2f7Stbbdev }
708*51c0b2f7Stbbdev 
709*51c0b2f7Stbbdev void doMallocReplacement()
710*51c0b2f7Stbbdev {
711*51c0b2f7Stbbdev     // Replace functions and keep backup of original code (separate for each runtime)
712*51c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR
713*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr70)
714*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr71)
715*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr80)
716*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr90)
717*51c0b2f7Stbbdev #endif
718*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr100)
719*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr110)
720*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr120)
721*51c0b2f7Stbbdev     __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_RELEASE(ucrtbase)
722*51c0b2f7Stbbdev 
723*51c0b2f7Stbbdev     // Replace functions without storing original code
724*51c0b2f7Stbbdev     for (size_t j = 0; j < arrayLength(modules_to_replace); j++) {
725*51c0b2f7Stbbdev         if (!modules_to_replace[j].doFuncReplacement)
726*51c0b2f7Stbbdev             continue;
727*51c0b2f7Stbbdev         for (size_t i = 0; i < arrayLength(c_routines_to_replace); i++)
728*51c0b2f7Stbbdev         {
729*51c0b2f7Stbbdev             ReplaceFunctionWithStore( modules_to_replace[j].name, c_routines_to_replace[i]._func, c_routines_to_replace[i]._fptr, NULL, NULL,  c_routines_to_replace[i]._on_error );
730*51c0b2f7Stbbdev         }
731*51c0b2f7Stbbdev         if ( strcmp(modules_to_replace[j].name, "ucrtbase.dll") == 0 ) {
732*51c0b2f7Stbbdev             HMODULE ucrtbase_handle = GetModuleHandle("ucrtbase.dll");
733*51c0b2f7Stbbdev             if (!ucrtbase_handle)
734*51c0b2f7Stbbdev                 continue;
735*51c0b2f7Stbbdev             // If _o_free function is present and patchable, redirect it to tbbmalloc as well
736*51c0b2f7Stbbdev             // This prevents issues with other _o_* functions which might allocate memory with malloc
737*51c0b2f7Stbbdev             if ( IsPrologueKnown("ucrtbase.dll", "_o_free", known_bytecodes, ucrtbase_handle)) {
738*51c0b2f7Stbbdev                 ReplaceFunctionWithStore( "ucrtbase.dll", "_o_free", (FUNCPTR)__TBB_malloc__o_free, known_bytecodes, (FUNCPTR*)&orig__o_free,  FRR_FAIL );
739*51c0b2f7Stbbdev             }
740*51c0b2f7Stbbdev             // Similarly for _free_base
741*51c0b2f7Stbbdev             if (IsPrologueKnown("ucrtbase.dll", "_free_base", known_bytecodes, ucrtbase_handle)) {
742*51c0b2f7Stbbdev                 ReplaceFunctionWithStore("ucrtbase.dll", "_free_base", (FUNCPTR)__TBB_malloc__free_base, known_bytecodes, (FUNCPTR*)&orig__free_base, FRR_FAIL);
743*51c0b2f7Stbbdev             }
744*51c0b2f7Stbbdev             // ucrtbase.dll does not export operator new/delete, so skip the rest of the loop.
745*51c0b2f7Stbbdev             continue;
746*51c0b2f7Stbbdev         }
747*51c0b2f7Stbbdev 
748*51c0b2f7Stbbdev         for (size_t i = 0; i < arrayLength(cxx_routines_to_replace); i++)
749*51c0b2f7Stbbdev         {
750*51c0b2f7Stbbdev #if !_WIN64
751*51c0b2f7Stbbdev             // in Microsoft* Visual Studio* 2012 and 2013 32-bit operator delete consists of 2 bytes only: short jump to free(ptr);
752*51c0b2f7Stbbdev             // replacement should be skipped for this particular case.
753*51c0b2f7Stbbdev             if ( ((strcmp(modules_to_replace[j].name, "msvcr110.dll") == 0) || (strcmp(modules_to_replace[j].name, "msvcr120.dll") == 0)) && (strcmp(cxx_routines_to_replace[i]._func, "??3@YAXPAX@Z") == 0) ) continue;
754*51c0b2f7Stbbdev             // in Microsoft* Visual Studio* 2013 32-bit operator delete[] consists of 2 bytes only: short jump to free(ptr);
755*51c0b2f7Stbbdev             // replacement should be skipped for this particular case.
756*51c0b2f7Stbbdev             if ( (strcmp(modules_to_replace[j].name, "msvcr120.dll") == 0) && (strcmp(cxx_routines_to_replace[i]._func, "??_V@YAXPAX@Z") == 0) ) continue;
757*51c0b2f7Stbbdev #endif
758*51c0b2f7Stbbdev             ReplaceFunctionWithStore( modules_to_replace[j].name, cxx_routines_to_replace[i]._func, cxx_routines_to_replace[i]._fptr, NULL, NULL,  cxx_routines_to_replace[i]._on_error );
759*51c0b2f7Stbbdev         }
760*51c0b2f7Stbbdev     }
761*51c0b2f7Stbbdev }
762*51c0b2f7Stbbdev 
763*51c0b2f7Stbbdev #endif // !__TBB_WIN8UI_SUPPORT
764*51c0b2f7Stbbdev 
765*51c0b2f7Stbbdev #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
766*51c0b2f7Stbbdev     // Suppress warning for UWP build ('main' signature found without threading model)
767*51c0b2f7Stbbdev     #pragma warning(push)
768*51c0b2f7Stbbdev     #pragma warning(disable:4447)
769*51c0b2f7Stbbdev #endif
770*51c0b2f7Stbbdev 
771*51c0b2f7Stbbdev extern "C" BOOL WINAPI DllMain( HINSTANCE hInst, DWORD callReason, LPVOID reserved )
772*51c0b2f7Stbbdev {
773*51c0b2f7Stbbdev 
774*51c0b2f7Stbbdev     if ( callReason==DLL_PROCESS_ATTACH && reserved && hInst ) {
775*51c0b2f7Stbbdev #if !__TBB_WIN8UI_SUPPORT
776*51c0b2f7Stbbdev         if (!tbb::detail::r1::GetBoolEnvironmentVariable("TBB_MALLOC_DISABLE_REPLACEMENT"))
777*51c0b2f7Stbbdev         {
778*51c0b2f7Stbbdev             doMallocReplacement();
779*51c0b2f7Stbbdev         }
780*51c0b2f7Stbbdev #endif // !__TBB_WIN8UI_SUPPORT
781*51c0b2f7Stbbdev     }
782*51c0b2f7Stbbdev 
783*51c0b2f7Stbbdev     return TRUE;
784*51c0b2f7Stbbdev }
785*51c0b2f7Stbbdev 
786*51c0b2f7Stbbdev #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
787*51c0b2f7Stbbdev     #pragma warning(pop)
788*51c0b2f7Stbbdev #endif
789*51c0b2f7Stbbdev 
790*51c0b2f7Stbbdev // Just to make the linker happy and link the DLL to the application
791*51c0b2f7Stbbdev extern "C" __declspec(dllexport) void __TBB_malloc_proxy()
792*51c0b2f7Stbbdev {
793*51c0b2f7Stbbdev 
794*51c0b2f7Stbbdev }
795*51c0b2f7Stbbdev 
796*51c0b2f7Stbbdev #endif //_WIN32
797