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