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