1 /* 2 Copyright (c) 2005-2020 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 "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