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 "oneapi/tbb/scalable_allocator.h" 45 #include "../tbb/environment.h" 46 47 #if !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) && !defined(__SUNPRO_CC) 48 #if TBB_USE_EXCEPTIONS 49 #error Compilation settings do not support exception handling. Please do not set TBB_USE_EXCEPTIONS macro or set it to 0. 50 #elif !defined(TBB_USE_EXCEPTIONS) 51 #define TBB_USE_EXCEPTIONS 0 52 #endif 53 #elif !defined(TBB_USE_EXCEPTIONS) 54 #define TBB_USE_EXCEPTIONS 1 55 #endif 56 57 #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || _WIN32 && !__TBB_WIN8UI_SUPPORT 58 /*** internal global operator new implementation (Linux, Windows) ***/ 59 #include <new> 60 61 // Synchronization primitives to protect original library pointers and new_handler 62 #include "../tbbmalloc/Synchronize.h" 63 // Use MallocMutex implementation 64 typedef MallocMutex ProxyMutex; 65 66 // Adds aliasing and copy attributes to function if available 67 #if defined(__has_attribute) 68 #if __has_attribute(__copy__) 69 #define __TBB_ALIAS_ATTR_COPY(name) __attribute__((alias (#name), __copy__(name))) 70 #endif 71 #endif 72 73 #ifndef __TBB_ALIAS_ATTR_COPY 74 #define __TBB_ALIAS_ATTR_COPY(name) __attribute__((alias (#name))) 75 #endif 76 77 // In case there is no std::get_new_handler function 78 // which provides synchronized access to std::new_handler 79 #if !__TBB_CPP11_GET_NEW_HANDLER_PRESENT 80 static ProxyMutex new_lock; 81 #endif 82 83 static inline void* InternalOperatorNew(size_t sz) { 84 void* res = scalable_malloc(sz); 85 #if TBB_USE_EXCEPTIONS 86 while (!res) { 87 std::new_handler handler; 88 #if __TBB_CPP11_GET_NEW_HANDLER_PRESENT 89 handler = std::get_new_handler(); 90 #else 91 { 92 ProxyMutex::scoped_lock lock(new_lock); 93 handler = std::set_new_handler(0); 94 std::set_new_handler(handler); 95 } 96 #endif 97 if (handler) { 98 (*handler)(); 99 } else { 100 throw std::bad_alloc(); 101 } 102 res = scalable_malloc(sz); 103 } 104 #endif /* TBB_USE_EXCEPTIONS */ 105 return res; 106 } 107 /*** end of internal global operator new implementation ***/ 108 #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || _WIN32 && !__TBB_WIN8UI_SUPPORT 109 110 #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 111 112 #ifndef __THROW 113 #define __THROW 114 #endif 115 116 /*** service functions and variables ***/ 117 #include <string.h> // for memset 118 #include <unistd.h> // for sysconf 119 120 static long memoryPageSize; 121 122 static inline void initPageSize() 123 { 124 memoryPageSize = sysconf(_SC_PAGESIZE); 125 } 126 127 #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED 128 #include <dlfcn.h> 129 #include <malloc.h> // mallinfo 130 131 /* __TBB_malloc_proxy used as a weak symbol by libtbbmalloc for: 132 1) detection that the proxy library is loaded 133 2) check that dlsym("malloc") found something different from our replacement malloc 134 */ 135 136 extern "C" void *__TBB_malloc_proxy(size_t) __TBB_ALIAS_ATTR_COPY(malloc); 137 138 static void *orig_msize; 139 140 #elif MALLOC_ZONE_OVERLOAD_ENABLED 141 142 #include "proxy_overload_osx.h" 143 144 #endif // MALLOC_ZONE_OVERLOAD_ENABLED 145 146 // Original (i.e., replaced) functions, 147 // they are never changed for MALLOC_ZONE_OVERLOAD_ENABLED. 148 static void *orig_free, 149 *orig_realloc; 150 151 #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED 152 #define ZONE_ARG 153 #define PREFIX(name) name 154 155 static void *orig_libc_free, 156 *orig_libc_realloc; 157 158 // We already tried to find ptr to original functions. 159 static std::atomic<bool> origFuncSearched{false}; 160 161 inline void InitOrigPointers() 162 { 163 // race is OK here, as different threads found same functions 164 if (!origFuncSearched.load(std::memory_order_acquire)) { 165 orig_free = dlsym(RTLD_NEXT, "free"); 166 orig_realloc = dlsym(RTLD_NEXT, "realloc"); 167 orig_msize = dlsym(RTLD_NEXT, "malloc_usable_size"); 168 orig_libc_free = dlsym(RTLD_NEXT, "__libc_free"); 169 orig_libc_realloc = dlsym(RTLD_NEXT, "__libc_realloc"); 170 171 origFuncSearched.store(true, std::memory_order_release); 172 } 173 } 174 175 /*** replacements for malloc and the family ***/ 176 extern "C" { 177 #elif MALLOC_ZONE_OVERLOAD_ENABLED 178 179 // each impl_* function has such 1st argument, it's unused 180 #define ZONE_ARG struct _malloc_zone_t *, 181 #define PREFIX(name) impl_##name 182 // not interested in original functions for zone overload 183 inline void InitOrigPointers() {} 184 185 #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED and MALLOC_ZONE_OVERLOAD_ENABLED 186 187 void *PREFIX(malloc)(ZONE_ARG size_t size) __THROW 188 { 189 return scalable_malloc(size); 190 } 191 192 void *PREFIX(calloc)(ZONE_ARG size_t num, size_t size) __THROW 193 { 194 return scalable_calloc(num, size); 195 } 196 197 void PREFIX(free)(ZONE_ARG void *object) __THROW 198 { 199 InitOrigPointers(); 200 __TBB_malloc_safer_free(object, (void (*)(void*))orig_free); 201 } 202 203 void *PREFIX(realloc)(ZONE_ARG void* ptr, size_t sz) __THROW 204 { 205 InitOrigPointers(); 206 return __TBB_malloc_safer_realloc(ptr, sz, orig_realloc); 207 } 208 209 /* The older *NIX interface for aligned allocations; 210 it's formally substituted by posix_memalign and deprecated, 211 so we do not expect it to cause cyclic dependency with C RTL. */ 212 void *PREFIX(memalign)(ZONE_ARG size_t alignment, size_t size) __THROW 213 { 214 return scalable_aligned_malloc(size, alignment); 215 } 216 217 /* valloc allocates memory aligned on a page boundary */ 218 void *PREFIX(valloc)(ZONE_ARG size_t size) __THROW 219 { 220 if (! memoryPageSize) initPageSize(); 221 222 return scalable_aligned_malloc(size, memoryPageSize); 223 } 224 225 #undef ZONE_ARG 226 #undef PREFIX 227 228 #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED 229 230 // match prototype from system headers 231 #if __ANDROID__ 232 size_t malloc_usable_size(const void *ptr) __THROW 233 #else 234 size_t malloc_usable_size(void *ptr) __THROW 235 #endif 236 { 237 InitOrigPointers(); 238 return __TBB_malloc_safer_msize(const_cast<void*>(ptr), (size_t (*)(void*))orig_msize); 239 } 240 241 int posix_memalign(void **memptr, size_t alignment, size_t size) __THROW 242 { 243 return scalable_posix_memalign(memptr, alignment, size); 244 } 245 246 /* pvalloc allocates smallest set of complete pages which can hold 247 the requested number of bytes. Result is aligned on page boundary. */ 248 void *pvalloc(size_t size) __THROW 249 { 250 if (! memoryPageSize) initPageSize(); 251 // align size up to the page size, 252 // pvalloc(0) returns 1 page, see man libmpatrol 253 size = size? ((size-1) | (memoryPageSize-1)) + 1 : memoryPageSize; 254 255 return scalable_aligned_malloc(size, memoryPageSize); 256 } 257 258 int mallopt(int /*param*/, int /*value*/) __THROW 259 { 260 return 1; 261 } 262 263 struct mallinfo mallinfo() __THROW 264 { 265 struct mallinfo m; 266 memset(&m, 0, sizeof(struct mallinfo)); 267 268 return m; 269 } 270 271 #if __ANDROID__ 272 // Android doesn't have malloc_usable_size, provide it to be compatible 273 // with Linux, in addition overload dlmalloc_usable_size() that presented 274 // under Android. 275 size_t dlmalloc_usable_size(const void *ptr) __TBB_ALIAS_ATTR_COPY(malloc_usable_size); 276 #else // __ANDROID__ 277 // TODO: consider using __typeof__ to guarantee the correct declaration types 278 // C11 function, supported starting GLIBC 2.16 279 void *aligned_alloc(size_t alignment, size_t size) __TBB_ALIAS_ATTR_COPY(memalign); 280 // Those non-standard functions are exported by GLIBC, and might be used 281 // in conjunction with standard malloc/free, so we must overload them. 282 // Bionic doesn't have them. Not removing from the linker scripts, 283 // as absent entry points are ignored by the linker. 284 285 void *__libc_malloc(size_t size) __TBB_ALIAS_ATTR_COPY(malloc); 286 void *__libc_calloc(size_t num, size_t size) __TBB_ALIAS_ATTR_COPY(calloc); 287 void *__libc_memalign(size_t alignment, size_t size) __TBB_ALIAS_ATTR_COPY(memalign); 288 void *__libc_pvalloc(size_t size) __TBB_ALIAS_ATTR_COPY(pvalloc); 289 void *__libc_valloc(size_t size) __TBB_ALIAS_ATTR_COPY(valloc); 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