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