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