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