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