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