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