151c0b2f7Stbbdev /* 2b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation 351c0b2f7Stbbdev 451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 551c0b2f7Stbbdev you may not use this file except in compliance with the License. 651c0b2f7Stbbdev You may obtain a copy of the License at 751c0b2f7Stbbdev 851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 951c0b2f7Stbbdev 1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351c0b2f7Stbbdev See the License for the specific language governing permissions and 1451c0b2f7Stbbdev limitations under the License. 1551c0b2f7Stbbdev */ 1651c0b2f7Stbbdev 1751c0b2f7Stbbdev #if __linux__ && !__ANDROID__ 1851c0b2f7Stbbdev // include <bits/c++config.h> indirectly so that <cstdlib> is not included 1951c0b2f7Stbbdev #include <cstddef> 2051c0b2f7Stbbdev // include <features.h> indirectly so that <stdlib.h> is not included 2151c0b2f7Stbbdev #include <unistd.h> 2251c0b2f7Stbbdev // Working around compiler issue with Anaconda's gcc 7.3 compiler package. 2351c0b2f7Stbbdev // New gcc ported for old libc may provide their inline implementation 2451c0b2f7Stbbdev // of aligned_alloc as required by new C++ standard, this makes it hard to 2551c0b2f7Stbbdev // redefine aligned_alloc here. However, running on systems with new libc 2651c0b2f7Stbbdev // version, it still needs it to be redefined, thus tricking system headers 2751c0b2f7Stbbdev #if defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 16) && _GLIBCXX_HAVE_ALIGNED_ALLOC 2851c0b2f7Stbbdev // tell <cstdlib> that there is no aligned_alloc 2951c0b2f7Stbbdev #undef _GLIBCXX_HAVE_ALIGNED_ALLOC 3051c0b2f7Stbbdev // trick <stdlib.h> to define another symbol instead 3151c0b2f7Stbbdev #define aligned_alloc __hidden_redefined_aligned_alloc 3251c0b2f7Stbbdev // Fix the state and undefine the trick 3351c0b2f7Stbbdev #include <cstdlib> 3451c0b2f7Stbbdev #undef aligned_alloc 3551c0b2f7Stbbdev #endif // defined(__GLIBC_PREREQ)&&!__GLIBC_PREREQ(2, 16)&&_GLIBCXX_HAVE_ALIGNED_ALLOC 3651c0b2f7Stbbdev #endif // __linux__ && !__ANDROID__ 3751c0b2f7Stbbdev 3851c0b2f7Stbbdev #include "proxy.h" 3951c0b2f7Stbbdev 4049e08aacStbbdev #include "oneapi/tbb/detail/_config.h" 4151c0b2f7Stbbdev #include "../tbb/environment.h" 4251c0b2f7Stbbdev 4351c0b2f7Stbbdev #if !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) && !defined(__SUNPRO_CC) 4451c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS 4551c0b2f7Stbbdev #error Compilation settings do not support exception handling. Please do not set TBB_USE_EXCEPTIONS macro or set it to 0. 4651c0b2f7Stbbdev #elif !defined(TBB_USE_EXCEPTIONS) 4751c0b2f7Stbbdev #define TBB_USE_EXCEPTIONS 0 4851c0b2f7Stbbdev #endif 4951c0b2f7Stbbdev #elif !defined(TBB_USE_EXCEPTIONS) 5051c0b2f7Stbbdev #define TBB_USE_EXCEPTIONS 1 5151c0b2f7Stbbdev #endif 5251c0b2f7Stbbdev 5351c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || _WIN32 && !__TBB_WIN8UI_SUPPORT 5451c0b2f7Stbbdev /*** internal global operator new implementation (Linux, Windows) ***/ 5551c0b2f7Stbbdev #include <new> 5651c0b2f7Stbbdev 5751c0b2f7Stbbdev // Synchronization primitives to protect original library pointers and new_handler 5851c0b2f7Stbbdev #include "../tbbmalloc/Synchronize.h" 5951c0b2f7Stbbdev // Use MallocMutex implementation 6051c0b2f7Stbbdev typedef MallocMutex ProxyMutex; 6151c0b2f7Stbbdev 62*478de5b1Stbbdev // Adds aliasing and copy attributes to function if available 63*478de5b1Stbbdev #if defined(__has_attribute) 64*478de5b1Stbbdev #if __has_attribute(__copy__) 65*478de5b1Stbbdev #define __TBB_ALIAS_ATTR_COPY(name) __attribute__((alias (#name), __copy__(name))) 66*478de5b1Stbbdev #endif 67*478de5b1Stbbdev #endif 68*478de5b1Stbbdev 69*478de5b1Stbbdev #ifndef __TBB_ALIAS_ATTR_COPY 70*478de5b1Stbbdev #define __TBB_ALIAS_ATTR_COPY(name) __attribute__((alias (#name))) 71*478de5b1Stbbdev #endif 72*478de5b1Stbbdev 7351c0b2f7Stbbdev // In case there is no std::get_new_handler function 7451c0b2f7Stbbdev // which provides synchronized access to std::new_handler 7551c0b2f7Stbbdev #if !__TBB_CPP11_GET_NEW_HANDLER_PRESENT 7651c0b2f7Stbbdev static ProxyMutex new_lock; 7751c0b2f7Stbbdev #endif 7851c0b2f7Stbbdev 7951c0b2f7Stbbdev static inline void* InternalOperatorNew(size_t sz) { 8051c0b2f7Stbbdev void* res = scalable_malloc(sz); 8151c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS 8251c0b2f7Stbbdev while (!res) { 8351c0b2f7Stbbdev std::new_handler handler; 8451c0b2f7Stbbdev #if __TBB_CPP11_GET_NEW_HANDLER_PRESENT 8551c0b2f7Stbbdev handler = std::get_new_handler(); 8651c0b2f7Stbbdev #else 8751c0b2f7Stbbdev { 8851c0b2f7Stbbdev ProxyMutex::scoped_lock lock(new_lock); 8951c0b2f7Stbbdev handler = std::set_new_handler(0); 9051c0b2f7Stbbdev std::set_new_handler(handler); 9151c0b2f7Stbbdev } 9251c0b2f7Stbbdev #endif 9351c0b2f7Stbbdev if (handler) { 9451c0b2f7Stbbdev (*handler)(); 9551c0b2f7Stbbdev } else { 9651c0b2f7Stbbdev throw std::bad_alloc(); 9751c0b2f7Stbbdev } 9851c0b2f7Stbbdev res = scalable_malloc(sz); 9951c0b2f7Stbbdev } 10051c0b2f7Stbbdev #endif /* TBB_USE_EXCEPTIONS */ 10151c0b2f7Stbbdev return res; 10251c0b2f7Stbbdev } 10351c0b2f7Stbbdev /*** end of internal global operator new implementation ***/ 10451c0b2f7Stbbdev #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || _WIN32 && !__TBB_WIN8UI_SUPPORT 10551c0b2f7Stbbdev 10651c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 10751c0b2f7Stbbdev 10851c0b2f7Stbbdev #ifndef __THROW 10951c0b2f7Stbbdev #define __THROW 11051c0b2f7Stbbdev #endif 11151c0b2f7Stbbdev 11251c0b2f7Stbbdev /*** service functions and variables ***/ 11351c0b2f7Stbbdev #include <string.h> // for memset 11451c0b2f7Stbbdev #include <unistd.h> // for sysconf 11551c0b2f7Stbbdev 11651c0b2f7Stbbdev static long memoryPageSize; 11751c0b2f7Stbbdev 11851c0b2f7Stbbdev static inline void initPageSize() 11951c0b2f7Stbbdev { 12051c0b2f7Stbbdev memoryPageSize = sysconf(_SC_PAGESIZE); 12151c0b2f7Stbbdev } 12251c0b2f7Stbbdev 12351c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED 12451c0b2f7Stbbdev #include <dlfcn.h> 12551c0b2f7Stbbdev #include <malloc.h> // mallinfo 12651c0b2f7Stbbdev 12751c0b2f7Stbbdev /* __TBB_malloc_proxy used as a weak symbol by libtbbmalloc for: 12851c0b2f7Stbbdev 1) detection that the proxy library is loaded 12951c0b2f7Stbbdev 2) check that dlsym("malloc") found something different from our replacement malloc 13051c0b2f7Stbbdev */ 13151c0b2f7Stbbdev 132*478de5b1Stbbdev extern "C" void *__TBB_malloc_proxy(size_t) __TBB_ALIAS_ATTR_COPY(malloc); 13351c0b2f7Stbbdev 13451c0b2f7Stbbdev static void *orig_msize; 13551c0b2f7Stbbdev 13651c0b2f7Stbbdev #elif MALLOC_ZONE_OVERLOAD_ENABLED 13751c0b2f7Stbbdev 13851c0b2f7Stbbdev #include "proxy_overload_osx.h" 13951c0b2f7Stbbdev 14051c0b2f7Stbbdev #endif // MALLOC_ZONE_OVERLOAD_ENABLED 14151c0b2f7Stbbdev 14251c0b2f7Stbbdev // Original (i.e., replaced) functions, 14351c0b2f7Stbbdev // they are never changed for MALLOC_ZONE_OVERLOAD_ENABLED. 14451c0b2f7Stbbdev static void *orig_free, 14551c0b2f7Stbbdev *orig_realloc; 14651c0b2f7Stbbdev 14751c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED 14851c0b2f7Stbbdev #define ZONE_ARG 14951c0b2f7Stbbdev #define PREFIX(name) name 15051c0b2f7Stbbdev 15151c0b2f7Stbbdev static void *orig_libc_free, 15251c0b2f7Stbbdev *orig_libc_realloc; 15351c0b2f7Stbbdev 15451c0b2f7Stbbdev // We already tried to find ptr to original functions. 15551c0b2f7Stbbdev static std::atomic<bool> origFuncSearched{false}; 15651c0b2f7Stbbdev 15751c0b2f7Stbbdev inline void InitOrigPointers() 15851c0b2f7Stbbdev { 15951c0b2f7Stbbdev // race is OK here, as different threads found same functions 16051c0b2f7Stbbdev if (!origFuncSearched.load(std::memory_order_acquire)) { 16151c0b2f7Stbbdev orig_free = dlsym(RTLD_NEXT, "free"); 16251c0b2f7Stbbdev orig_realloc = dlsym(RTLD_NEXT, "realloc"); 16351c0b2f7Stbbdev orig_msize = dlsym(RTLD_NEXT, "malloc_usable_size"); 16451c0b2f7Stbbdev orig_libc_free = dlsym(RTLD_NEXT, "__libc_free"); 16551c0b2f7Stbbdev orig_libc_realloc = dlsym(RTLD_NEXT, "__libc_realloc"); 16651c0b2f7Stbbdev 16751c0b2f7Stbbdev origFuncSearched.store(true, std::memory_order_release); 16851c0b2f7Stbbdev } 16951c0b2f7Stbbdev } 17051c0b2f7Stbbdev 17151c0b2f7Stbbdev /*** replacements for malloc and the family ***/ 17251c0b2f7Stbbdev extern "C" { 17351c0b2f7Stbbdev #elif MALLOC_ZONE_OVERLOAD_ENABLED 17451c0b2f7Stbbdev 17551c0b2f7Stbbdev // each impl_* function has such 1st argument, it's unused 17651c0b2f7Stbbdev #define ZONE_ARG struct _malloc_zone_t *, 17751c0b2f7Stbbdev #define PREFIX(name) impl_##name 17851c0b2f7Stbbdev // not interested in original functions for zone overload 17951c0b2f7Stbbdev inline void InitOrigPointers() {} 18051c0b2f7Stbbdev 18151c0b2f7Stbbdev #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED and MALLOC_ZONE_OVERLOAD_ENABLED 18251c0b2f7Stbbdev 18351c0b2f7Stbbdev void *PREFIX(malloc)(ZONE_ARG size_t size) __THROW 18451c0b2f7Stbbdev { 18551c0b2f7Stbbdev return scalable_malloc(size); 18651c0b2f7Stbbdev } 18751c0b2f7Stbbdev 18851c0b2f7Stbbdev void *PREFIX(calloc)(ZONE_ARG size_t num, size_t size) __THROW 18951c0b2f7Stbbdev { 19051c0b2f7Stbbdev return scalable_calloc(num, size); 19151c0b2f7Stbbdev } 19251c0b2f7Stbbdev 19351c0b2f7Stbbdev void PREFIX(free)(ZONE_ARG void *object) __THROW 19451c0b2f7Stbbdev { 19551c0b2f7Stbbdev InitOrigPointers(); 19651c0b2f7Stbbdev __TBB_malloc_safer_free(object, (void (*)(void*))orig_free); 19751c0b2f7Stbbdev } 19851c0b2f7Stbbdev 19951c0b2f7Stbbdev void *PREFIX(realloc)(ZONE_ARG void* ptr, size_t sz) __THROW 20051c0b2f7Stbbdev { 20151c0b2f7Stbbdev InitOrigPointers(); 20251c0b2f7Stbbdev return __TBB_malloc_safer_realloc(ptr, sz, orig_realloc); 20351c0b2f7Stbbdev } 20451c0b2f7Stbbdev 20551c0b2f7Stbbdev /* The older *NIX interface for aligned allocations; 20651c0b2f7Stbbdev it's formally substituted by posix_memalign and deprecated, 20751c0b2f7Stbbdev so we do not expect it to cause cyclic dependency with C RTL. */ 20851c0b2f7Stbbdev void *PREFIX(memalign)(ZONE_ARG size_t alignment, size_t size) __THROW 20951c0b2f7Stbbdev { 21051c0b2f7Stbbdev return scalable_aligned_malloc(size, alignment); 21151c0b2f7Stbbdev } 21251c0b2f7Stbbdev 21351c0b2f7Stbbdev /* valloc allocates memory aligned on a page boundary */ 21451c0b2f7Stbbdev void *PREFIX(valloc)(ZONE_ARG size_t size) __THROW 21551c0b2f7Stbbdev { 21651c0b2f7Stbbdev if (! memoryPageSize) initPageSize(); 21751c0b2f7Stbbdev 21851c0b2f7Stbbdev return scalable_aligned_malloc(size, memoryPageSize); 21951c0b2f7Stbbdev } 22051c0b2f7Stbbdev 22151c0b2f7Stbbdev #undef ZONE_ARG 22251c0b2f7Stbbdev #undef PREFIX 22351c0b2f7Stbbdev 22451c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED 22551c0b2f7Stbbdev 22651c0b2f7Stbbdev // match prototype from system headers 22751c0b2f7Stbbdev #if __ANDROID__ 22851c0b2f7Stbbdev size_t malloc_usable_size(const void *ptr) __THROW 22951c0b2f7Stbbdev #else 23051c0b2f7Stbbdev size_t malloc_usable_size(void *ptr) __THROW 23151c0b2f7Stbbdev #endif 23251c0b2f7Stbbdev { 23351c0b2f7Stbbdev InitOrigPointers(); 23451c0b2f7Stbbdev return __TBB_malloc_safer_msize(const_cast<void*>(ptr), (size_t (*)(void*))orig_msize); 23551c0b2f7Stbbdev } 23651c0b2f7Stbbdev 23751c0b2f7Stbbdev int posix_memalign(void **memptr, size_t alignment, size_t size) __THROW 23851c0b2f7Stbbdev { 23951c0b2f7Stbbdev return scalable_posix_memalign(memptr, alignment, size); 24051c0b2f7Stbbdev } 24151c0b2f7Stbbdev 24251c0b2f7Stbbdev /* pvalloc allocates smallest set of complete pages which can hold 24351c0b2f7Stbbdev the requested number of bytes. Result is aligned on page boundary. */ 24451c0b2f7Stbbdev void *pvalloc(size_t size) __THROW 24551c0b2f7Stbbdev { 24651c0b2f7Stbbdev if (! memoryPageSize) initPageSize(); 24751c0b2f7Stbbdev // align size up to the page size, 24851c0b2f7Stbbdev // pvalloc(0) returns 1 page, see man libmpatrol 24951c0b2f7Stbbdev size = size? ((size-1) | (memoryPageSize-1)) + 1 : memoryPageSize; 25051c0b2f7Stbbdev 25151c0b2f7Stbbdev return scalable_aligned_malloc(size, memoryPageSize); 25251c0b2f7Stbbdev } 25351c0b2f7Stbbdev 25451c0b2f7Stbbdev int mallopt(int /*param*/, int /*value*/) __THROW 25551c0b2f7Stbbdev { 25651c0b2f7Stbbdev return 1; 25751c0b2f7Stbbdev } 25851c0b2f7Stbbdev 25951c0b2f7Stbbdev struct mallinfo mallinfo() __THROW 26051c0b2f7Stbbdev { 26151c0b2f7Stbbdev struct mallinfo m; 26251c0b2f7Stbbdev memset(&m, 0, sizeof(struct mallinfo)); 26351c0b2f7Stbbdev 26451c0b2f7Stbbdev return m; 26551c0b2f7Stbbdev } 26651c0b2f7Stbbdev 26751c0b2f7Stbbdev #if __ANDROID__ 26851c0b2f7Stbbdev // Android doesn't have malloc_usable_size, provide it to be compatible 26951c0b2f7Stbbdev // with Linux, in addition overload dlmalloc_usable_size() that presented 27051c0b2f7Stbbdev // under Android. 271*478de5b1Stbbdev size_t dlmalloc_usable_size(const void *ptr) __TBB_ALIAS_ATTR_COPY(malloc_usable_size); 27251c0b2f7Stbbdev #else // __ANDROID__ 273*478de5b1Stbbdev // TODO: consider using __typeof__ to guarantee the correct declaration types 27451c0b2f7Stbbdev // C11 function, supported starting GLIBC 2.16 275*478de5b1Stbbdev void *aligned_alloc(size_t alignment, size_t size) __TBB_ALIAS_ATTR_COPY(memalign); 27651c0b2f7Stbbdev // Those non-standard functions are exported by GLIBC, and might be used 277*478de5b1Stbbdev // in conjunction with standard malloc/free, so we must overload them. 27851c0b2f7Stbbdev // Bionic doesn't have them. Not removing from the linker scripts, 27951c0b2f7Stbbdev // as absent entry points are ignored by the linker. 28051c0b2f7Stbbdev 281*478de5b1Stbbdev void *__libc_malloc(size_t size) __TBB_ALIAS_ATTR_COPY(malloc); 282*478de5b1Stbbdev void *__libc_calloc(size_t num, size_t size) __TBB_ALIAS_ATTR_COPY(calloc); 283*478de5b1Stbbdev void *__libc_memalign(size_t alignment, size_t size) __TBB_ALIAS_ATTR_COPY(memalign); 284*478de5b1Stbbdev void *__libc_pvalloc(size_t size) __TBB_ALIAS_ATTR_COPY(pvalloc); 285*478de5b1Stbbdev void *__libc_valloc(size_t size) __TBB_ALIAS_ATTR_COPY(valloc); 28651c0b2f7Stbbdev 28751c0b2f7Stbbdev // call original __libc_* to support naive replacement of free via __libc_free etc 28851c0b2f7Stbbdev void __libc_free(void *ptr) 28951c0b2f7Stbbdev { 29051c0b2f7Stbbdev InitOrigPointers(); 29151c0b2f7Stbbdev __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_libc_free); 29251c0b2f7Stbbdev } 29351c0b2f7Stbbdev 29451c0b2f7Stbbdev void *__libc_realloc(void *ptr, size_t size) 29551c0b2f7Stbbdev { 29651c0b2f7Stbbdev InitOrigPointers(); 29751c0b2f7Stbbdev return __TBB_malloc_safer_realloc(ptr, size, orig_libc_realloc); 29851c0b2f7Stbbdev } 29951c0b2f7Stbbdev #endif // !__ANDROID__ 30051c0b2f7Stbbdev 30151c0b2f7Stbbdev } /* extern "C" */ 30251c0b2f7Stbbdev 30351c0b2f7Stbbdev /*** replacements for global operators new and delete ***/ 30451c0b2f7Stbbdev 30551c0b2f7Stbbdev void* operator new(size_t sz) { 30651c0b2f7Stbbdev return InternalOperatorNew(sz); 30751c0b2f7Stbbdev } 30851c0b2f7Stbbdev void* operator new[](size_t sz) { 30951c0b2f7Stbbdev return InternalOperatorNew(sz); 31051c0b2f7Stbbdev } 31151c0b2f7Stbbdev void operator delete(void* ptr) noexcept { 31251c0b2f7Stbbdev InitOrigPointers(); 31351c0b2f7Stbbdev __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free); 31451c0b2f7Stbbdev } 31551c0b2f7Stbbdev void operator delete[](void* ptr) noexcept { 31651c0b2f7Stbbdev InitOrigPointers(); 31751c0b2f7Stbbdev __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free); 31851c0b2f7Stbbdev } 31951c0b2f7Stbbdev void* operator new(size_t sz, const std::nothrow_t&) noexcept { 32051c0b2f7Stbbdev return scalable_malloc(sz); 32151c0b2f7Stbbdev } 32251c0b2f7Stbbdev void* operator new[](std::size_t sz, const std::nothrow_t&) noexcept { 32351c0b2f7Stbbdev return scalable_malloc(sz); 32451c0b2f7Stbbdev } 32551c0b2f7Stbbdev void operator delete(void* ptr, const std::nothrow_t&) noexcept { 32651c0b2f7Stbbdev InitOrigPointers(); 32751c0b2f7Stbbdev __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free); 32851c0b2f7Stbbdev } 32951c0b2f7Stbbdev void operator delete[](void* ptr, const std::nothrow_t&) noexcept { 33051c0b2f7Stbbdev InitOrigPointers(); 33151c0b2f7Stbbdev __TBB_malloc_safer_free(ptr, (void (*)(void*))orig_free); 33251c0b2f7Stbbdev } 33351c0b2f7Stbbdev 33451c0b2f7Stbbdev #endif /* MALLOC_UNIXLIKE_OVERLOAD_ENABLED */ 33551c0b2f7Stbbdev #endif /* MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED */ 33651c0b2f7Stbbdev 33751c0b2f7Stbbdev #ifdef _WIN32 33851c0b2f7Stbbdev #include <windows.h> 33951c0b2f7Stbbdev 34051c0b2f7Stbbdev #if !__TBB_WIN8UI_SUPPORT 34151c0b2f7Stbbdev 34251c0b2f7Stbbdev #include <stdio.h> 34351c0b2f7Stbbdev 34451c0b2f7Stbbdev #include "function_replacement.h" 34551c0b2f7Stbbdev 34651c0b2f7Stbbdev template<typename T, size_t N> // generic function to find length of array 34751c0b2f7Stbbdev inline size_t arrayLength(const T(&)[N]) { 34851c0b2f7Stbbdev return N; 34951c0b2f7Stbbdev } 35051c0b2f7Stbbdev 35151c0b2f7Stbbdev void __TBB_malloc_safer_delete( void *ptr) 35251c0b2f7Stbbdev { 35351c0b2f7Stbbdev __TBB_malloc_safer_free( ptr, NULL ); 35451c0b2f7Stbbdev } 35551c0b2f7Stbbdev 35651c0b2f7Stbbdev void* safer_aligned_malloc( size_t size, size_t alignment ) 35751c0b2f7Stbbdev { 35851c0b2f7Stbbdev // workaround for "is power of 2 pow N" bug that accepts zeros 35951c0b2f7Stbbdev return scalable_aligned_malloc( size, alignment>sizeof(size_t*)?alignment:sizeof(size_t*) ); 36051c0b2f7Stbbdev } 36151c0b2f7Stbbdev 36251c0b2f7Stbbdev // we do not support _expand(); 36351c0b2f7Stbbdev void* safer_expand( void *, size_t ) 36451c0b2f7Stbbdev { 36551c0b2f7Stbbdev return NULL; 36651c0b2f7Stbbdev } 36751c0b2f7Stbbdev 36851c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(CRTLIB) \ 36951c0b2f7Stbbdev void (*orig_free_##CRTLIB)(void*); \ 37051c0b2f7Stbbdev void __TBB_malloc_safer_free_##CRTLIB(void *ptr) \ 37151c0b2f7Stbbdev { \ 37251c0b2f7Stbbdev __TBB_malloc_safer_free( ptr, orig_free_##CRTLIB ); \ 37351c0b2f7Stbbdev } \ 37451c0b2f7Stbbdev \ 37551c0b2f7Stbbdev void (*orig__aligned_free_##CRTLIB)(void*); \ 37651c0b2f7Stbbdev void __TBB_malloc_safer__aligned_free_##CRTLIB(void *ptr) \ 37751c0b2f7Stbbdev { \ 37851c0b2f7Stbbdev __TBB_malloc_safer_free( ptr, orig__aligned_free_##CRTLIB ); \ 37951c0b2f7Stbbdev } \ 38051c0b2f7Stbbdev \ 38151c0b2f7Stbbdev size_t (*orig__msize_##CRTLIB)(void*); \ 38251c0b2f7Stbbdev size_t __TBB_malloc_safer__msize_##CRTLIB(void *ptr) \ 38351c0b2f7Stbbdev { \ 38451c0b2f7Stbbdev return __TBB_malloc_safer_msize( ptr, orig__msize_##CRTLIB ); \ 38551c0b2f7Stbbdev } \ 38651c0b2f7Stbbdev \ 38751c0b2f7Stbbdev size_t (*orig__aligned_msize_##CRTLIB)(void*, size_t, size_t); \ 38851c0b2f7Stbbdev size_t __TBB_malloc_safer__aligned_msize_##CRTLIB( void *ptr, size_t alignment, size_t offset) \ 38951c0b2f7Stbbdev { \ 39051c0b2f7Stbbdev return __TBB_malloc_safer_aligned_msize( ptr, alignment, offset, orig__aligned_msize_##CRTLIB ); \ 39151c0b2f7Stbbdev } \ 39251c0b2f7Stbbdev \ 39351c0b2f7Stbbdev void* __TBB_malloc_safer_realloc_##CRTLIB( void *ptr, size_t size ) \ 39451c0b2f7Stbbdev { \ 39551c0b2f7Stbbdev orig_ptrs func_ptrs = {orig_free_##CRTLIB, orig__msize_##CRTLIB}; \ 39651c0b2f7Stbbdev return __TBB_malloc_safer_realloc( ptr, size, &func_ptrs ); \ 39751c0b2f7Stbbdev } \ 39851c0b2f7Stbbdev \ 39951c0b2f7Stbbdev void* __TBB_malloc_safer__aligned_realloc_##CRTLIB( void *ptr, size_t size, size_t alignment ) \ 40051c0b2f7Stbbdev { \ 40151c0b2f7Stbbdev orig_aligned_ptrs func_ptrs = {orig__aligned_free_##CRTLIB, orig__aligned_msize_##CRTLIB}; \ 40251c0b2f7Stbbdev return __TBB_malloc_safer_aligned_realloc( ptr, size, alignment, &func_ptrs ); \ 40351c0b2f7Stbbdev } 40451c0b2f7Stbbdev 40551c0b2f7Stbbdev // Only for ucrtbase: substitution for _o_free 40651c0b2f7Stbbdev void (*orig__o_free)(void*); 40751c0b2f7Stbbdev void __TBB_malloc__o_free(void *ptr) 40851c0b2f7Stbbdev { 40951c0b2f7Stbbdev __TBB_malloc_safer_free( ptr, orig__o_free ); 41051c0b2f7Stbbdev } 41151c0b2f7Stbbdev // Only for ucrtbase: substitution for _free_base 41251c0b2f7Stbbdev void(*orig__free_base)(void*); 41351c0b2f7Stbbdev void __TBB_malloc__free_base(void *ptr) 41451c0b2f7Stbbdev { 41551c0b2f7Stbbdev __TBB_malloc_safer_free(ptr, orig__free_base); 41651c0b2f7Stbbdev } 41751c0b2f7Stbbdev 41851c0b2f7Stbbdev // Size limit is MAX_PATTERN_SIZE (28) byte codes / 56 symbols per line. 41951c0b2f7Stbbdev // * can be used to match any digit in byte codes. 42051c0b2f7Stbbdev // # followed by several * indicate a relative address that needs to be corrected. 42151c0b2f7Stbbdev // Purpose of the pattern is to mark an instruction bound; it should consist of several 42251c0b2f7Stbbdev // full instructions plus one extra byte code. It's not required for the patterns 42351c0b2f7Stbbdev // to be unique (i.e., it's OK to have same pattern for unrelated functions). 42451c0b2f7Stbbdev // TODO: use hot patch prologues if exist 42551c0b2f7Stbbdev const char* known_bytecodes[] = { 42651c0b2f7Stbbdev #if _WIN64 42751c0b2f7Stbbdev // "========================================================" - 56 symbols 42851c0b2f7Stbbdev "4883EC284885C974", // release free() 42951c0b2f7Stbbdev "4883EC284885C975", // release _msize() 43051c0b2f7Stbbdev "4885C974375348", // release free() 8.0.50727.42, 10.0 43151c0b2f7Stbbdev "E907000000CCCC", // release _aligned_msize(), _aligned_free() ucrtbase.dll 43251c0b2f7Stbbdev "C7442410000000008B", // release free() ucrtbase.dll 10.0.14393.33 43351c0b2f7Stbbdev "E90B000000CCCC", // release _msize() ucrtbase.dll 10.0.14393.33 43451c0b2f7Stbbdev "48895C24085748", // release _aligned_msize() ucrtbase.dll 10.0.14393.33 43551c0b2f7Stbbdev "E903000000CCCC", // release _aligned_msize() ucrtbase.dll 10.0.16299.522 43651c0b2f7Stbbdev "48894C24084883EC28BA", // debug prologue 43751c0b2f7Stbbdev "4C894424184889542410", // debug _aligned_msize() 10.0 43851c0b2f7Stbbdev "48894C24084883EC2848", // debug _aligned_free 10.0 43951c0b2f7Stbbdev "488BD1488D0D#*******E9", // _o_free(), ucrtbase.dll 44051c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR 44151c0b2f7Stbbdev "48895C2408574883EC3049", // release _aligned_msize 9.0 44251c0b2f7Stbbdev "4883EC384885C975", // release _msize() 9.0 44351c0b2f7Stbbdev "4C8BC1488B0DA6E4040033", // an old win64 SDK 44451c0b2f7Stbbdev #endif 44551c0b2f7Stbbdev #else // _WIN32 44651c0b2f7Stbbdev // "========================================================" - 56 symbols 44751c0b2f7Stbbdev "8BFF558BEC8B", // multiple 44851c0b2f7Stbbdev "8BFF558BEC83", // release free() & _msize() 10.0.40219.325, _msize() ucrtbase.dll 44951c0b2f7Stbbdev "8BFF558BECFF", // release _aligned_msize ucrtbase.dll 45051c0b2f7Stbbdev "8BFF558BEC51", // release free() & _msize() ucrtbase.dll 10.0.14393.33 45151c0b2f7Stbbdev "558BEC8B450885C074", // release _aligned_free 11.0 45251c0b2f7Stbbdev "558BEC837D08000F", // release _msize() 11.0.51106.1 45351c0b2f7Stbbdev "558BEC837D08007419FF", // release free() 11.0.50727.1 45451c0b2f7Stbbdev "558BEC8B450885C075", // release _aligned_msize() 11.0.50727.1 45551c0b2f7Stbbdev "558BEC6A018B", // debug free() & _msize() 11.0 45651c0b2f7Stbbdev "558BEC8B451050", // debug _aligned_msize() 11.0 45751c0b2f7Stbbdev "558BEC8B450850", // debug _aligned_free 11.0 45851c0b2f7Stbbdev "8BFF558BEC6A", // debug free() & _msize() 10.0.40219.325 45951c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR 46051c0b2f7Stbbdev "6A1868********E8", // release free() 8.0.50727.4053, 9.0 46151c0b2f7Stbbdev "6A1C68********E8", // release _msize() 8.0.50727.4053, 9.0 46251c0b2f7Stbbdev #endif 46351c0b2f7Stbbdev #endif // _WIN64/_WIN32 46451c0b2f7Stbbdev NULL 46551c0b2f7Stbbdev }; 46651c0b2f7Stbbdev 46751c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,function_name,dbgsuffix) \ 46851c0b2f7Stbbdev ReplaceFunctionWithStore( #CRT_VER #dbgsuffix ".dll", #function_name, \ 46951c0b2f7Stbbdev (FUNCPTR)__TBB_malloc_safer_##function_name##_##CRT_VER##dbgsuffix, \ 47051c0b2f7Stbbdev known_bytecodes, (FUNCPTR*)&orig_##function_name##_##CRT_VER##dbgsuffix ); 47151c0b2f7Stbbdev 47251c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_NO_FALLBACK(CRT_VER,function_name,dbgsuffix) \ 47351c0b2f7Stbbdev ReplaceFunctionWithStore( #CRT_VER #dbgsuffix ".dll", #function_name, \ 47451c0b2f7Stbbdev (FUNCPTR)__TBB_malloc_safer_##function_name##_##CRT_VER##dbgsuffix, 0, NULL ); 47551c0b2f7Stbbdev 47651c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_REDIRECT(CRT_VER,function_name,dest_func,dbgsuffix) \ 47751c0b2f7Stbbdev ReplaceFunctionWithStore( #CRT_VER #dbgsuffix ".dll", #function_name, \ 47851c0b2f7Stbbdev (FUNCPTR)__TBB_malloc_safer_##dest_func##_##CRT_VER##dbgsuffix, 0, NULL ); 47951c0b2f7Stbbdev 48051c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_IMPL(CRT_VER,dbgsuffix) \ 48151c0b2f7Stbbdev if (BytecodesAreKnown(#CRT_VER #dbgsuffix ".dll")) { \ 48251c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,free,dbgsuffix) \ 48351c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,_msize,dbgsuffix) \ 48451c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_NO_FALLBACK(CRT_VER,realloc,dbgsuffix) \ 48551c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,_aligned_free,dbgsuffix) \ 48651c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY(CRT_VER,_aligned_msize,dbgsuffix) \ 48751c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_ENTRY_NO_FALLBACK(CRT_VER,_aligned_realloc,dbgsuffix) \ 48851c0b2f7Stbbdev } else \ 48951c0b2f7Stbbdev SkipReplacement(#CRT_VER #dbgsuffix ".dll"); 49051c0b2f7Stbbdev 49151c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_RELEASE(CRT_VER) __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_IMPL(CRT_VER,) 49251c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_DEBUG(CRT_VER) __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_IMPL(CRT_VER,d) 49351c0b2f7Stbbdev 49451c0b2f7Stbbdev #define __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(CRT_VER) \ 49551c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_RELEASE(CRT_VER) \ 49651c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_DEBUG(CRT_VER) 49751c0b2f7Stbbdev 49851c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR 49951c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr70d); 50051c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr70); 50151c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr71d); 50251c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr71); 50351c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr80d); 50451c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr80); 50551c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr90d); 50651c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr90); 50751c0b2f7Stbbdev #endif 50851c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr100d); 50951c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr100); 51051c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr110d); 51151c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr110); 51251c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr120d); 51351c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(msvcr120); 51451c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_WRAPPER(ucrtbase); 51551c0b2f7Stbbdev 51651c0b2f7Stbbdev /*** replacements for global operators new and delete ***/ 51751c0b2f7Stbbdev 51851c0b2f7Stbbdev #if _MSC_VER && !defined(__INTEL_COMPILER) 51951c0b2f7Stbbdev #pragma warning( push ) 52051c0b2f7Stbbdev #pragma warning( disable : 4290 ) 52151c0b2f7Stbbdev #endif 52251c0b2f7Stbbdev 52351c0b2f7Stbbdev /*** operator new overloads internals (Linux, Windows) ***/ 52451c0b2f7Stbbdev 52551c0b2f7Stbbdev void* operator_new(size_t sz) { 52651c0b2f7Stbbdev return InternalOperatorNew(sz); 52751c0b2f7Stbbdev } 52851c0b2f7Stbbdev void* operator_new_arr(size_t sz) { 52951c0b2f7Stbbdev return InternalOperatorNew(sz); 53051c0b2f7Stbbdev } 53151c0b2f7Stbbdev void operator_delete(void* ptr) noexcept { 53251c0b2f7Stbbdev __TBB_malloc_safer_delete(ptr); 53351c0b2f7Stbbdev } 53451c0b2f7Stbbdev #if _MSC_VER && !defined(__INTEL_COMPILER) 53551c0b2f7Stbbdev #pragma warning( pop ) 53651c0b2f7Stbbdev #endif 53751c0b2f7Stbbdev 53851c0b2f7Stbbdev void operator_delete_arr(void* ptr) noexcept { 53951c0b2f7Stbbdev __TBB_malloc_safer_delete(ptr); 54051c0b2f7Stbbdev } 54151c0b2f7Stbbdev void* operator_new_t(size_t sz, const std::nothrow_t&) noexcept { 54251c0b2f7Stbbdev return scalable_malloc(sz); 54351c0b2f7Stbbdev } 54451c0b2f7Stbbdev void* operator_new_arr_t(std::size_t sz, const std::nothrow_t&) noexcept { 54551c0b2f7Stbbdev return scalable_malloc(sz); 54651c0b2f7Stbbdev } 54751c0b2f7Stbbdev void operator_delete_t(void* ptr, const std::nothrow_t&) noexcept { 54851c0b2f7Stbbdev __TBB_malloc_safer_delete(ptr); 54951c0b2f7Stbbdev } 55051c0b2f7Stbbdev void operator_delete_arr_t(void* ptr, const std::nothrow_t&) noexcept { 55151c0b2f7Stbbdev __TBB_malloc_safer_delete(ptr); 55251c0b2f7Stbbdev } 55351c0b2f7Stbbdev 55451c0b2f7Stbbdev struct Module { 55551c0b2f7Stbbdev const char *name; 55651c0b2f7Stbbdev bool doFuncReplacement; // do replacement in the DLL 55751c0b2f7Stbbdev }; 55851c0b2f7Stbbdev 55951c0b2f7Stbbdev Module modules_to_replace[] = { 56051c0b2f7Stbbdev {"msvcr100d.dll", true}, 56151c0b2f7Stbbdev {"msvcr100.dll", true}, 56251c0b2f7Stbbdev {"msvcr110d.dll", true}, 56351c0b2f7Stbbdev {"msvcr110.dll", true}, 56451c0b2f7Stbbdev {"msvcr120d.dll", true}, 56551c0b2f7Stbbdev {"msvcr120.dll", true}, 56651c0b2f7Stbbdev {"ucrtbase.dll", true}, 56751c0b2f7Stbbdev // "ucrtbased.dll" is not supported because of problems with _dbg functions 56851c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR 56951c0b2f7Stbbdev {"msvcr90d.dll", true}, 57051c0b2f7Stbbdev {"msvcr90.dll", true}, 57151c0b2f7Stbbdev {"msvcr80d.dll", true}, 57251c0b2f7Stbbdev {"msvcr80.dll", true}, 57351c0b2f7Stbbdev {"msvcr70d.dll", true}, 57451c0b2f7Stbbdev {"msvcr70.dll", true}, 57551c0b2f7Stbbdev {"msvcr71d.dll", true}, 57651c0b2f7Stbbdev {"msvcr71.dll", true}, 57751c0b2f7Stbbdev #endif 57851c0b2f7Stbbdev #if __TBB_TODO 57951c0b2f7Stbbdev // TODO: Try enabling replacement for non-versioned system binaries below 58051c0b2f7Stbbdev {"msvcrtd.dll", true}, 58151c0b2f7Stbbdev {"msvcrt.dll", true}, 58251c0b2f7Stbbdev #endif 58351c0b2f7Stbbdev }; 58451c0b2f7Stbbdev 58551c0b2f7Stbbdev /* 58651c0b2f7Stbbdev We need to replace following functions: 58751c0b2f7Stbbdev malloc 58851c0b2f7Stbbdev calloc 58951c0b2f7Stbbdev _aligned_malloc 59051c0b2f7Stbbdev _expand (by dummy implementation) 59151c0b2f7Stbbdev ??2@YAPAXI@Z operator new (ia32) 59251c0b2f7Stbbdev ??_U@YAPAXI@Z void * operator new[] (size_t size) (ia32) 59351c0b2f7Stbbdev ??3@YAXPAX@Z operator delete (ia32) 59451c0b2f7Stbbdev ??_V@YAXPAX@Z operator delete[] (ia32) 59551c0b2f7Stbbdev ??2@YAPEAX_K@Z void * operator new(unsigned __int64) (intel64) 59651c0b2f7Stbbdev ??_V@YAXPEAX@Z void * operator new[](unsigned __int64) (intel64) 59751c0b2f7Stbbdev ??3@YAXPEAX@Z operator delete (intel64) 59851c0b2f7Stbbdev ??_V@YAXPEAX@Z operator delete[] (intel64) 59951c0b2f7Stbbdev ??2@YAPAXIABUnothrow_t@std@@@Z void * operator new (size_t sz, const std::nothrow_t&) throw() (optional) 60051c0b2f7Stbbdev ??_U@YAPAXIABUnothrow_t@std@@@Z void * operator new[] (size_t sz, const std::nothrow_t&) throw() (optional) 60151c0b2f7Stbbdev 60251c0b2f7Stbbdev and these functions have runtime-specific replacement: 60351c0b2f7Stbbdev realloc 60451c0b2f7Stbbdev free 60551c0b2f7Stbbdev _msize 60651c0b2f7Stbbdev _aligned_realloc 60751c0b2f7Stbbdev _aligned_free 60851c0b2f7Stbbdev _aligned_msize 60951c0b2f7Stbbdev */ 61051c0b2f7Stbbdev 61151c0b2f7Stbbdev typedef struct FRData_t { 61251c0b2f7Stbbdev //char *_module; 61351c0b2f7Stbbdev const char *_func; 61451c0b2f7Stbbdev FUNCPTR _fptr; 61551c0b2f7Stbbdev FRR_ON_ERROR _on_error; 61651c0b2f7Stbbdev } FRDATA; 61751c0b2f7Stbbdev 61851c0b2f7Stbbdev FRDATA c_routines_to_replace[] = { 61951c0b2f7Stbbdev { "malloc", (FUNCPTR)scalable_malloc, FRR_FAIL }, 62051c0b2f7Stbbdev { "calloc", (FUNCPTR)scalable_calloc, FRR_FAIL }, 62151c0b2f7Stbbdev { "_aligned_malloc", (FUNCPTR)safer_aligned_malloc, FRR_FAIL }, 62251c0b2f7Stbbdev { "_expand", (FUNCPTR)safer_expand, FRR_IGNORE }, 62351c0b2f7Stbbdev }; 62451c0b2f7Stbbdev 62551c0b2f7Stbbdev FRDATA cxx_routines_to_replace[] = { 62651c0b2f7Stbbdev #if _WIN64 62751c0b2f7Stbbdev { "??2@YAPEAX_K@Z", (FUNCPTR)operator_new, FRR_FAIL }, 62851c0b2f7Stbbdev { "??_U@YAPEAX_K@Z", (FUNCPTR)operator_new_arr, FRR_FAIL }, 62951c0b2f7Stbbdev { "??3@YAXPEAX@Z", (FUNCPTR)operator_delete, FRR_FAIL }, 63051c0b2f7Stbbdev { "??_V@YAXPEAX@Z", (FUNCPTR)operator_delete_arr, FRR_FAIL }, 63151c0b2f7Stbbdev #else 63251c0b2f7Stbbdev { "??2@YAPAXI@Z", (FUNCPTR)operator_new, FRR_FAIL }, 63351c0b2f7Stbbdev { "??_U@YAPAXI@Z", (FUNCPTR)operator_new_arr, FRR_FAIL }, 63451c0b2f7Stbbdev { "??3@YAXPAX@Z", (FUNCPTR)operator_delete, FRR_FAIL }, 63551c0b2f7Stbbdev { "??_V@YAXPAX@Z", (FUNCPTR)operator_delete_arr, FRR_FAIL }, 63651c0b2f7Stbbdev #endif 63751c0b2f7Stbbdev { "??2@YAPAXIABUnothrow_t@std@@@Z", (FUNCPTR)operator_new_t, FRR_IGNORE }, 63851c0b2f7Stbbdev { "??_U@YAPAXIABUnothrow_t@std@@@Z", (FUNCPTR)operator_new_arr_t, FRR_IGNORE } 63951c0b2f7Stbbdev }; 64051c0b2f7Stbbdev 64151c0b2f7Stbbdev #ifndef UNICODE 64251c0b2f7Stbbdev typedef char unicode_char_t; 64351c0b2f7Stbbdev #define WCHAR_SPEC "%s" 64451c0b2f7Stbbdev #else 64551c0b2f7Stbbdev typedef wchar_t unicode_char_t; 64651c0b2f7Stbbdev #define WCHAR_SPEC "%ls" 64751c0b2f7Stbbdev #endif 64851c0b2f7Stbbdev 64951c0b2f7Stbbdev // Check that we recognize bytecodes that should be replaced by trampolines. 65051c0b2f7Stbbdev // If some functions have unknown prologue patterns, replacement should not be done. 65151c0b2f7Stbbdev bool BytecodesAreKnown(const unicode_char_t *dllName) 65251c0b2f7Stbbdev { 65351c0b2f7Stbbdev const char *funcName[] = {"free", "_msize", "_aligned_free", "_aligned_msize", 0}; 65451c0b2f7Stbbdev HMODULE module = GetModuleHandle(dllName); 65551c0b2f7Stbbdev 65651c0b2f7Stbbdev if (!module) 65751c0b2f7Stbbdev return false; 65851c0b2f7Stbbdev for (int i=0; funcName[i]; i++) 65951c0b2f7Stbbdev if (! IsPrologueKnown(dllName, funcName[i], known_bytecodes, module)) { 66051c0b2f7Stbbdev fprintf(stderr, "TBBmalloc: skip allocation functions replacement in " WCHAR_SPEC 66151c0b2f7Stbbdev ": unknown prologue for function " WCHAR_SPEC "\n", dllName, funcName[i]); 66251c0b2f7Stbbdev return false; 66351c0b2f7Stbbdev } 66451c0b2f7Stbbdev return true; 66551c0b2f7Stbbdev } 66651c0b2f7Stbbdev 66751c0b2f7Stbbdev void SkipReplacement(const unicode_char_t *dllName) 66851c0b2f7Stbbdev { 66951c0b2f7Stbbdev #ifndef UNICODE 67051c0b2f7Stbbdev const char *dllStr = dllName; 67151c0b2f7Stbbdev #else 67251c0b2f7Stbbdev const size_t sz = 128; // all DLL name must fit 67351c0b2f7Stbbdev 67451c0b2f7Stbbdev char buffer[sz]; 67551c0b2f7Stbbdev size_t real_sz; 67651c0b2f7Stbbdev char *dllStr = buffer; 67751c0b2f7Stbbdev 67851c0b2f7Stbbdev errno_t ret = wcstombs_s(&real_sz, dllStr, sz, dllName, sz-1); 67951c0b2f7Stbbdev __TBB_ASSERT(!ret, "Dll name conversion failed"); 68051c0b2f7Stbbdev #endif 68151c0b2f7Stbbdev 68251c0b2f7Stbbdev for (size_t i=0; i<arrayLength(modules_to_replace); i++) 68351c0b2f7Stbbdev if (!strcmp(modules_to_replace[i].name, dllStr)) { 68451c0b2f7Stbbdev modules_to_replace[i].doFuncReplacement = false; 68551c0b2f7Stbbdev break; 68651c0b2f7Stbbdev } 68751c0b2f7Stbbdev } 68851c0b2f7Stbbdev 68951c0b2f7Stbbdev void ReplaceFunctionWithStore( const unicode_char_t *dllName, const char *funcName, FUNCPTR newFunc, const char ** opcodes, FUNCPTR* origFunc, FRR_ON_ERROR on_error = FRR_FAIL ) 69051c0b2f7Stbbdev { 69151c0b2f7Stbbdev FRR_TYPE res = ReplaceFunction( dllName, funcName, newFunc, opcodes, origFunc ); 69251c0b2f7Stbbdev 69351c0b2f7Stbbdev if (res == FRR_OK || res == FRR_NODLL || (res == FRR_NOFUNC && on_error == FRR_IGNORE)) 69451c0b2f7Stbbdev return; 69551c0b2f7Stbbdev 69651c0b2f7Stbbdev fprintf(stderr, "Failed to %s function %s in module %s\n", 69751c0b2f7Stbbdev res==FRR_NOFUNC? "find" : "replace", funcName, dllName); 69851c0b2f7Stbbdev 69951c0b2f7Stbbdev // Unable to replace a required function 70051c0b2f7Stbbdev // Aborting because incomplete replacement of memory management functions 70151c0b2f7Stbbdev // may leave the program in an invalid state 70251c0b2f7Stbbdev abort(); 70351c0b2f7Stbbdev } 70451c0b2f7Stbbdev 70551c0b2f7Stbbdev void doMallocReplacement() 70651c0b2f7Stbbdev { 70751c0b2f7Stbbdev // Replace functions and keep backup of original code (separate for each runtime) 70851c0b2f7Stbbdev #if __TBB_OVERLOAD_OLD_MSVCR 70951c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr70) 71051c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr71) 71151c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr80) 71251c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr90) 71351c0b2f7Stbbdev #endif 71451c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr100) 71551c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr110) 71651c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL(msvcr120) 71751c0b2f7Stbbdev __TBB_ORIG_ALLOCATOR_REPLACEMENT_CALL_RELEASE(ucrtbase) 71851c0b2f7Stbbdev 71951c0b2f7Stbbdev // Replace functions without storing original code 72051c0b2f7Stbbdev for (size_t j = 0; j < arrayLength(modules_to_replace); j++) { 72151c0b2f7Stbbdev if (!modules_to_replace[j].doFuncReplacement) 72251c0b2f7Stbbdev continue; 72351c0b2f7Stbbdev for (size_t i = 0; i < arrayLength(c_routines_to_replace); i++) 72451c0b2f7Stbbdev { 72551c0b2f7Stbbdev 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 ); 72651c0b2f7Stbbdev } 72751c0b2f7Stbbdev if ( strcmp(modules_to_replace[j].name, "ucrtbase.dll") == 0 ) { 72851c0b2f7Stbbdev HMODULE ucrtbase_handle = GetModuleHandle("ucrtbase.dll"); 72951c0b2f7Stbbdev if (!ucrtbase_handle) 73051c0b2f7Stbbdev continue; 73151c0b2f7Stbbdev // If _o_free function is present and patchable, redirect it to tbbmalloc as well 73251c0b2f7Stbbdev // This prevents issues with other _o_* functions which might allocate memory with malloc 73351c0b2f7Stbbdev if ( IsPrologueKnown("ucrtbase.dll", "_o_free", known_bytecodes, ucrtbase_handle)) { 73451c0b2f7Stbbdev ReplaceFunctionWithStore( "ucrtbase.dll", "_o_free", (FUNCPTR)__TBB_malloc__o_free, known_bytecodes, (FUNCPTR*)&orig__o_free, FRR_FAIL ); 73551c0b2f7Stbbdev } 73651c0b2f7Stbbdev // Similarly for _free_base 73751c0b2f7Stbbdev if (IsPrologueKnown("ucrtbase.dll", "_free_base", known_bytecodes, ucrtbase_handle)) { 73851c0b2f7Stbbdev ReplaceFunctionWithStore("ucrtbase.dll", "_free_base", (FUNCPTR)__TBB_malloc__free_base, known_bytecodes, (FUNCPTR*)&orig__free_base, FRR_FAIL); 73951c0b2f7Stbbdev } 74051c0b2f7Stbbdev // ucrtbase.dll does not export operator new/delete, so skip the rest of the loop. 74151c0b2f7Stbbdev continue; 74251c0b2f7Stbbdev } 74351c0b2f7Stbbdev 74451c0b2f7Stbbdev for (size_t i = 0; i < arrayLength(cxx_routines_to_replace); i++) 74551c0b2f7Stbbdev { 74651c0b2f7Stbbdev #if !_WIN64 74751c0b2f7Stbbdev // in Microsoft* Visual Studio* 2012 and 2013 32-bit operator delete consists of 2 bytes only: short jump to free(ptr); 74851c0b2f7Stbbdev // replacement should be skipped for this particular case. 74951c0b2f7Stbbdev 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; 75051c0b2f7Stbbdev // in Microsoft* Visual Studio* 2013 32-bit operator delete[] consists of 2 bytes only: short jump to free(ptr); 75151c0b2f7Stbbdev // replacement should be skipped for this particular case. 75251c0b2f7Stbbdev if ( (strcmp(modules_to_replace[j].name, "msvcr120.dll") == 0) && (strcmp(cxx_routines_to_replace[i]._func, "??_V@YAXPAX@Z") == 0) ) continue; 75351c0b2f7Stbbdev #endif 75451c0b2f7Stbbdev 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 ); 75551c0b2f7Stbbdev } 75651c0b2f7Stbbdev } 75751c0b2f7Stbbdev } 75851c0b2f7Stbbdev 75951c0b2f7Stbbdev #endif // !__TBB_WIN8UI_SUPPORT 76051c0b2f7Stbbdev 76151c0b2f7Stbbdev #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 76251c0b2f7Stbbdev // Suppress warning for UWP build ('main' signature found without threading model) 76351c0b2f7Stbbdev #pragma warning(push) 76451c0b2f7Stbbdev #pragma warning(disable:4447) 76551c0b2f7Stbbdev #endif 76651c0b2f7Stbbdev 76751c0b2f7Stbbdev extern "C" BOOL WINAPI DllMain( HINSTANCE hInst, DWORD callReason, LPVOID reserved ) 76851c0b2f7Stbbdev { 76951c0b2f7Stbbdev 77051c0b2f7Stbbdev if ( callReason==DLL_PROCESS_ATTACH && reserved && hInst ) { 77151c0b2f7Stbbdev #if !__TBB_WIN8UI_SUPPORT 77251c0b2f7Stbbdev if (!tbb::detail::r1::GetBoolEnvironmentVariable("TBB_MALLOC_DISABLE_REPLACEMENT")) 77351c0b2f7Stbbdev { 77451c0b2f7Stbbdev doMallocReplacement(); 77551c0b2f7Stbbdev } 77651c0b2f7Stbbdev #endif // !__TBB_WIN8UI_SUPPORT 77751c0b2f7Stbbdev } 77851c0b2f7Stbbdev 77951c0b2f7Stbbdev return TRUE; 78051c0b2f7Stbbdev } 78151c0b2f7Stbbdev 78251c0b2f7Stbbdev #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 78351c0b2f7Stbbdev #pragma warning(pop) 78451c0b2f7Stbbdev #endif 78551c0b2f7Stbbdev 78651c0b2f7Stbbdev // Just to make the linker happy and link the DLL to the application 78751c0b2f7Stbbdev extern "C" __declspec(dllexport) void __TBB_malloc_proxy() 78851c0b2f7Stbbdev { 78951c0b2f7Stbbdev 79051c0b2f7Stbbdev } 79151c0b2f7Stbbdev 79251c0b2f7Stbbdev #endif //_WIN32 793