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