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 //! \file test_malloc_overload.cpp
1851c0b2f7Stbbdev //! \brief Test for [memory_allocation] functionality
1951c0b2f7Stbbdev 
2051c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1
2151c0b2f7Stbbdev 
2251c0b2f7Stbbdev #if (_WIN32 || _WIN64)
23*478de5b1Stbbdev #define _CRT_SECURE_NO_WARNINGS
2451c0b2f7Stbbdev // As the test is intentionally build with /EHs-, suppress multiple VS2005's
2551c0b2f7Stbbdev // warnings like C4530: C++ exception handler used, but unwind semantics are not enabled
2651c0b2f7Stbbdev #if defined(_MSC_VER) && !__INTEL_COMPILER
2751c0b2f7Stbbdev /* ICC 10.1 and 11.0 generates code that uses std::_Raise_handler,
2851c0b2f7Stbbdev    but it's only defined in libcpmt(d), which the test doesn't linked with.
2951c0b2f7Stbbdev  */
3051c0b2f7Stbbdev #undef  _HAS_EXCEPTIONS
3151c0b2f7Stbbdev #define _HAS_EXCEPTIONS _CPPUNWIND
3251c0b2f7Stbbdev #endif
3351c0b2f7Stbbdev // to use strdup w/o warnings
3451c0b2f7Stbbdev #define _CRT_NONSTDC_NO_DEPRECATE 1
3551c0b2f7Stbbdev #endif // _WIN32 || _WIN64
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev #define _ISOC11_SOURCE 1 // to get C11 declarations for GLIBC
3851c0b2f7Stbbdev 
3951c0b2f7Stbbdev #include "common/allocator_overload.h"
4051c0b2f7Stbbdev 
4151c0b2f7Stbbdev #if MALLOC_WINDOWS_OVERLOAD_ENABLED
4251c0b2f7Stbbdev #include "tbb/tbbmalloc_proxy.h"
4351c0b2f7Stbbdev #endif
4451c0b2f7Stbbdev 
4551c0b2f7Stbbdev #include "common/test.h"
4651c0b2f7Stbbdev 
4751c0b2f7Stbbdev #if !HARNESS_SKIP_TEST
4851c0b2f7Stbbdev 
4951c0b2f7Stbbdev #if __ANDROID__
5051c0b2f7Stbbdev   #include <android/api-level.h> // for __ANDROID_API__
5151c0b2f7Stbbdev #endif
5251c0b2f7Stbbdev 
5351c0b2f7Stbbdev #define __TBB_POSIX_MEMALIGN_PRESENT (__linux__ && !__ANDROID__) || __APPLE__
5451c0b2f7Stbbdev #define __TBB_PVALLOC_PRESENT __linux__ && !__ANDROID__
5551c0b2f7Stbbdev #if __GLIBC__
5651c0b2f7Stbbdev   // aligned_alloc available since GLIBC 2.16
5751c0b2f7Stbbdev   #define __TBB_ALIGNED_ALLOC_PRESENT __GLIBC_PREREQ(2, 16)
5851c0b2f7Stbbdev #endif // __GLIBC__
5951c0b2f7Stbbdev  // later Android doesn't have valloc or dlmalloc_usable_size
6051c0b2f7Stbbdev #define __TBB_VALLOC_PRESENT (__linux__ && __ANDROID_API__<21) || __APPLE__
6151c0b2f7Stbbdev #define __TBB_DLMALLOC_USABLE_SIZE_PRESENT  __ANDROID__ && __ANDROID_API__<21
6251c0b2f7Stbbdev 
6351c0b2f7Stbbdev #include "common/utils.h"
6451c0b2f7Stbbdev #include "common/utils_report.h"
6551c0b2f7Stbbdev #include "common/utils_assert.h"
6651c0b2f7Stbbdev #include "common/utils_env.h"
6751c0b2f7Stbbdev 
6851c0b2f7Stbbdev #include <stdlib.h>
6951c0b2f7Stbbdev #include <string.h>
7051c0b2f7Stbbdev #if !__APPLE__
7151c0b2f7Stbbdev #include <malloc.h>
7251c0b2f7Stbbdev #endif
7351c0b2f7Stbbdev #include <stdio.h>
7451c0b2f7Stbbdev #include <new>
7551c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
7651c0b2f7Stbbdev #include <unistd.h> // for sysconf
7751c0b2f7Stbbdev #include <dlfcn.h>
7851c0b2f7Stbbdev #endif
7951c0b2f7Stbbdev 
8051c0b2f7Stbbdev #if __linux__
8151c0b2f7Stbbdev #include <stdint.h> // for uintptr_t
8251c0b2f7Stbbdev 
8351c0b2f7Stbbdev extern "C" {
8451c0b2f7Stbbdev void *__libc_malloc(size_t size);
8551c0b2f7Stbbdev void *__libc_realloc(void *ptr, size_t size);
8651c0b2f7Stbbdev void *__libc_calloc(size_t num, size_t size);
8751c0b2f7Stbbdev void __libc_free(void *ptr);
8851c0b2f7Stbbdev void *__libc_memalign(size_t alignment, size_t size);
8951c0b2f7Stbbdev void *__libc_pvalloc(size_t size);
9051c0b2f7Stbbdev void *__libc_valloc(size_t size);
9151c0b2f7Stbbdev #if __TBB_DLMALLOC_USABLE_SIZE_PRESENT
9251c0b2f7Stbbdev #define malloc_usable_size(p) dlmalloc_usable_size(p)
9351c0b2f7Stbbdev size_t dlmalloc_usable_size(const void *ptr);
9451c0b2f7Stbbdev #endif
9551c0b2f7Stbbdev }
9651c0b2f7Stbbdev 
9751c0b2f7Stbbdev #elif __APPLE__
9851c0b2f7Stbbdev 
9951c0b2f7Stbbdev #include <malloc/malloc.h>
10051c0b2f7Stbbdev #define malloc_usable_size(p) malloc_size(p)
10151c0b2f7Stbbdev 
10251c0b2f7Stbbdev #elif _WIN32
10351c0b2f7Stbbdev #include <stddef.h>
10451c0b2f7Stbbdev #if __MINGW32__
10551c0b2f7Stbbdev #include <unistd.h>
10651c0b2f7Stbbdev #else
10751c0b2f7Stbbdev typedef unsigned __int16 uint16_t;
10851c0b2f7Stbbdev typedef unsigned __int32 uint32_t;
10951c0b2f7Stbbdev typedef unsigned __int64 uint64_t;
11051c0b2f7Stbbdev #endif
11151c0b2f7Stbbdev 
11251c0b2f7Stbbdev #endif /* OS selection */
11351c0b2f7Stbbdev 
11451c0b2f7Stbbdev #if _WIN32
11551c0b2f7Stbbdev // On Windows, the trick with string "dependency on msvcpXX.dll" is necessary to create
11651c0b2f7Stbbdev // dependency on msvcpXX.dll, for sake of a regression test.
11751c0b2f7Stbbdev // On Linux, C++ RTL headers are undesirable because of breaking strict ANSI mode.
11851c0b2f7Stbbdev #if defined(_MSC_VER) && _MSC_VER >= 1300 && _MSC_VER <= 1310 && !defined(__INTEL_COMPILER)
11951c0b2f7Stbbdev /* Fixing compilation error reported by VS2003 for exception class
12051c0b2f7Stbbdev    when _HAS_EXCEPTIONS is 0:
12151c0b2f7Stbbdev    bad_cast that inherited from exception is not in std namespace.
12251c0b2f7Stbbdev */
12351c0b2f7Stbbdev using namespace std;
12451c0b2f7Stbbdev #endif
12551c0b2f7Stbbdev #include <string>
12651c0b2f7Stbbdev #include <set>
12751c0b2f7Stbbdev #include <sstream>
12851c0b2f7Stbbdev #endif
12951c0b2f7Stbbdev 
13049e08aacStbbdev #include "oneapi/tbb/detail/_utils.h"  // tbb::detail::is_aligned
13151c0b2f7Stbbdev #include "src/tbbmalloc/shared_utils.h"  // alignDown, alignUp, estimatedCacheLineSize
13251c0b2f7Stbbdev 
13351c0b2f7Stbbdev /* start of code replicated from src/tbbmalloc */
13451c0b2f7Stbbdev 
13551c0b2f7Stbbdev class BackRefIdx { // composite index to backreference array
13651c0b2f7Stbbdev private:
13751c0b2f7Stbbdev     uint16_t master;      // index in BackRefMaster
13851c0b2f7Stbbdev     uint16_t largeObj:1;  // is this object "large"?
13951c0b2f7Stbbdev     uint16_t offset  :15; // offset from beginning of BackRefBlock
14051c0b2f7Stbbdev public:
14151c0b2f7Stbbdev     BackRefIdx() : master((uint16_t)-1) {}
14251c0b2f7Stbbdev     bool isInvalid() { return master == (uint16_t)-1; }
14351c0b2f7Stbbdev     bool isLargeObject() const { return largeObj; }
14451c0b2f7Stbbdev     uint16_t getMaster() const { return master; }
14551c0b2f7Stbbdev     uint16_t getOffset() const { return offset; }
14651c0b2f7Stbbdev 
14751c0b2f7Stbbdev     // only newBackRef can modify BackRefIdx
14851c0b2f7Stbbdev     static BackRefIdx newBackRef(bool largeObj);
14951c0b2f7Stbbdev };
15051c0b2f7Stbbdev 
15151c0b2f7Stbbdev class MemoryPool;
15251c0b2f7Stbbdev class ExtMemoryPool;
15351c0b2f7Stbbdev 
15451c0b2f7Stbbdev struct BlockI {
15551c0b2f7Stbbdev     intptr_t     blockState[2];
15651c0b2f7Stbbdev };
15751c0b2f7Stbbdev 
15851c0b2f7Stbbdev struct LargeMemoryBlock : public BlockI {
15951c0b2f7Stbbdev     MemoryPool       *pool;          // owner pool
16051c0b2f7Stbbdev     LargeMemoryBlock *next,          // ptrs in list of cached blocks
16151c0b2f7Stbbdev                      *prev,
16251c0b2f7Stbbdev                      *gPrev,         // in pool's global list
16351c0b2f7Stbbdev                      *gNext;
16451c0b2f7Stbbdev     uintptr_t         age;           // age of block while in cache
16551c0b2f7Stbbdev     size_t            objectSize;    // the size requested by a client
16651c0b2f7Stbbdev     size_t            unalignedSize; // the size requested from getMemory
16751c0b2f7Stbbdev     bool              fromMapMemory;
16851c0b2f7Stbbdev     BackRefIdx        backRefIdx;    // cached here, used copy is in LargeObjectHdr
16951c0b2f7Stbbdev     void registerInPool(ExtMemoryPool *extMemPool);
17051c0b2f7Stbbdev     void unregisterFromPool(ExtMemoryPool *extMemPool);
17151c0b2f7Stbbdev };
17251c0b2f7Stbbdev 
17351c0b2f7Stbbdev struct LargeObjectHdr {
17451c0b2f7Stbbdev     LargeMemoryBlock *memoryBlock;
17551c0b2f7Stbbdev     /* Have to duplicate it here from CachedObjectHdr,
17651c0b2f7Stbbdev        as backreference must be checked without further pointer dereference.
17751c0b2f7Stbbdev        Points to LargeObjectHdr. */
17851c0b2f7Stbbdev     BackRefIdx       backRefIdx;
17951c0b2f7Stbbdev };
18051c0b2f7Stbbdev 
18151c0b2f7Stbbdev /*
18251c0b2f7Stbbdev  * Objects of size minLargeObjectSize and larger are considered large objects.
18351c0b2f7Stbbdev  */
18451c0b2f7Stbbdev const uintptr_t blockSize = 16*1024;
18551c0b2f7Stbbdev const uint32_t fittingAlignment = rml::internal::estimatedCacheLineSize;
18651c0b2f7Stbbdev #define SET_FITTING_SIZE(N) ( (blockSize-2*rml::internal::estimatedCacheLineSize)/N ) & ~(fittingAlignment-1)
18751c0b2f7Stbbdev const uint32_t fittingSize5 = SET_FITTING_SIZE(2); // 8128/8064
18851c0b2f7Stbbdev #undef SET_FITTING_SIZE
18951c0b2f7Stbbdev const uint32_t minLargeObjectSize = fittingSize5 + 1;
19051c0b2f7Stbbdev 
19151c0b2f7Stbbdev /* end of code replicated from src/tbbmalloc */
19251c0b2f7Stbbdev 
19351c0b2f7Stbbdev static void scalableMallocCheckSize(void *object, size_t size)
19451c0b2f7Stbbdev {
19551c0b2f7Stbbdev #if __clang__
19651c0b2f7Stbbdev     // This prevents Clang from throwing out the calls to new & delete in CheckNewDeleteOverload().
19751c0b2f7Stbbdev     static void *v = object;
19851c0b2f7Stbbdev     utils::suppress_unused_warning(v);
19951c0b2f7Stbbdev #endif
20051c0b2f7Stbbdev     REQUIRE(object);
20151c0b2f7Stbbdev     if (size >= minLargeObjectSize) {
20251c0b2f7Stbbdev         LargeMemoryBlock *lmb = ((LargeObjectHdr*)object-1)->memoryBlock;
20351c0b2f7Stbbdev         REQUIRE((uintptr_t(lmb)<uintptr_t(((LargeObjectHdr*)object-1)) && lmb->objectSize >= size));
20451c0b2f7Stbbdev     }
20551c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
20651c0b2f7Stbbdev     REQUIRE(malloc_usable_size(object) >= size);
20751c0b2f7Stbbdev #elif MALLOC_WINDOWS_OVERLOAD_ENABLED
20851c0b2f7Stbbdev     // Check that _msize works correctly
20951c0b2f7Stbbdev     REQUIRE(_msize(object) >= size);
21051c0b2f7Stbbdev     REQUIRE((size < 8 || _aligned_msize(object,8,0) >= size));
21151c0b2f7Stbbdev #endif
21251c0b2f7Stbbdev }
21351c0b2f7Stbbdev 
21451c0b2f7Stbbdev void CheckStdFuncOverload(void *(*malloc_p)(size_t), void *(*calloc_p)(size_t, size_t),
21551c0b2f7Stbbdev                           void *(*realloc_p)(void *, size_t), void (*free_p)(void *))
21651c0b2f7Stbbdev {
21751c0b2f7Stbbdev     void *ptr = malloc_p(minLargeObjectSize);
21851c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
21951c0b2f7Stbbdev     free(ptr);
22051c0b2f7Stbbdev 
22151c0b2f7Stbbdev     ptr = calloc_p(minLargeObjectSize, 2);
22251c0b2f7Stbbdev     scalableMallocCheckSize(ptr, 2*minLargeObjectSize);
22351c0b2f7Stbbdev     void *ptr1 = realloc_p(ptr, 10*minLargeObjectSize);
22451c0b2f7Stbbdev     scalableMallocCheckSize(ptr1, 10*minLargeObjectSize);
22551c0b2f7Stbbdev     free_p(ptr1);
22651c0b2f7Stbbdev }
22751c0b2f7Stbbdev 
22851c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
22951c0b2f7Stbbdev 
23051c0b2f7Stbbdev void CheckMemalignFuncOverload(void *(*memalign_p)(size_t, size_t),
23151c0b2f7Stbbdev                                void (*free_p)(void*))
23251c0b2f7Stbbdev {
23351c0b2f7Stbbdev     void *ptr = memalign_p(128, 4*minLargeObjectSize);
23451c0b2f7Stbbdev     scalableMallocCheckSize(ptr, 4*minLargeObjectSize);
23551c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 128));
23651c0b2f7Stbbdev     free_p(ptr);
23751c0b2f7Stbbdev }
23851c0b2f7Stbbdev 
23951c0b2f7Stbbdev void CheckVallocFuncOverload(void *(*valloc_p)(size_t), void (*free_p)(void*))
24051c0b2f7Stbbdev {
24151c0b2f7Stbbdev     void *ptr = valloc_p(minLargeObjectSize);
24251c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
24351c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, sysconf(_SC_PAGESIZE)));
24451c0b2f7Stbbdev     free_p(ptr);
24551c0b2f7Stbbdev }
24651c0b2f7Stbbdev 
24751c0b2f7Stbbdev void CheckPvalloc(void *(*pvalloc_p)(size_t), void (*free_p)(void*))
24851c0b2f7Stbbdev {
24951c0b2f7Stbbdev     const long memoryPageSize = sysconf(_SC_PAGESIZE);
25051c0b2f7Stbbdev     // request large object with not power-of-2 size
25151c0b2f7Stbbdev     const size_t largeSz = alignUp(minLargeObjectSize, 16*1024) + 1;
25251c0b2f7Stbbdev 
25351c0b2f7Stbbdev     for (size_t sz = 0; sz<=largeSz; sz+=largeSz) {
25451c0b2f7Stbbdev         void *ptr = pvalloc_p(sz);
25551c0b2f7Stbbdev         scalableMallocCheckSize(ptr, sz? alignUp(sz, memoryPageSize) : memoryPageSize);
25651c0b2f7Stbbdev         REQUIRE(tbb::detail::is_aligned(ptr, memoryPageSize));
25751c0b2f7Stbbdev         free_p(ptr);
25851c0b2f7Stbbdev     }
25951c0b2f7Stbbdev }
26051c0b2f7Stbbdev 
26151c0b2f7Stbbdev #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
26251c0b2f7Stbbdev 
26351c0b2f7Stbbdev // regression test: on macOS scalable_free() treated small aligned object,
26451c0b2f7Stbbdev // placed in large block, as small block
26551c0b2f7Stbbdev void CheckFreeAligned() {
26651c0b2f7Stbbdev     size_t sz[] = {8, 4*1024, 16*1024, 0};
26751c0b2f7Stbbdev     size_t align[] = {8, 4*1024, 16*1024, 0};
26851c0b2f7Stbbdev 
26951c0b2f7Stbbdev     for (int s=0; sz[s]; s++)
27051c0b2f7Stbbdev         for (int a=0; align[a]; a++) {
27151c0b2f7Stbbdev             void *ptr = NULL;
27251c0b2f7Stbbdev #if __TBB_POSIX_MEMALIGN_PRESENT
27351c0b2f7Stbbdev             int ret = posix_memalign(&ptr, align[a], sz[s]);
27451c0b2f7Stbbdev             REQUIRE(!ret);
27551c0b2f7Stbbdev #elif MALLOC_WINDOWS_OVERLOAD_ENABLED
27651c0b2f7Stbbdev             ptr = _aligned_malloc(sz[s], align[a]);
27751c0b2f7Stbbdev #endif
27851c0b2f7Stbbdev             REQUIRE(tbb::detail::is_aligned(ptr, align[a]));
27951c0b2f7Stbbdev             free(ptr);
28051c0b2f7Stbbdev         }
28151c0b2f7Stbbdev }
28251c0b2f7Stbbdev 
28351c0b2f7Stbbdev #if __ANDROID__
28451c0b2f7Stbbdev // Workaround for an issue with strdup somehow bypassing our malloc replacement on Android.
28551c0b2f7Stbbdev char *strdup(const char *str) {
28651c0b2f7Stbbdev     REPORT( "Known issue: malloc replacement does not work for strdup on Android.\n" );
28751c0b2f7Stbbdev     size_t len = strlen(str)+1;
28851c0b2f7Stbbdev     void *new_str = malloc(len);
28951c0b2f7Stbbdev     return new_str ? reinterpret_cast<char *>(memcpy(new_str, str, len)) : 0;
29051c0b2f7Stbbdev }
29151c0b2f7Stbbdev #endif
29251c0b2f7Stbbdev 
29351c0b2f7Stbbdev #if __APPLE__
29451c0b2f7Stbbdev #include <mach/mach.h>
29551c0b2f7Stbbdev 
29651c0b2f7Stbbdev // regression test: malloc_usable_size() that was passed to zone interface
29751c0b2f7Stbbdev // called system malloc_usable_size(), so for object that was not allocated
29851c0b2f7Stbbdev // by tbbmalloc non-zero was returned, so such objects were passed to
29951c0b2f7Stbbdev // tbbmalloc's free(), that is incorrect
30051c0b2f7Stbbdev void TestZoneOverload() {
30151c0b2f7Stbbdev     vm_address_t *zones;
30251c0b2f7Stbbdev     unsigned zones_num;
30351c0b2f7Stbbdev 
30451c0b2f7Stbbdev     kern_return_t ret = malloc_get_all_zones(mach_task_self(), NULL, &zones, &zones_num);
30551c0b2f7Stbbdev     REQUIRE((!ret && zones_num>1));
30651c0b2f7Stbbdev     malloc_zone_t *sys_zone = (malloc_zone_t*)zones[1];
30751c0b2f7Stbbdev     REQUIRE_MESSAGE(strcmp("tbbmalloc", malloc_get_zone_name(sys_zone)), "zone 1 expected to be not tbbmalloc");
30851c0b2f7Stbbdev     void *p = malloc_zone_malloc(sys_zone, 16);
30951c0b2f7Stbbdev     free(p);
31051c0b2f7Stbbdev }
31151c0b2f7Stbbdev #else
31251c0b2f7Stbbdev #define TestZoneOverload()
31351c0b2f7Stbbdev #endif
31451c0b2f7Stbbdev 
31551c0b2f7Stbbdev #if _WIN32
31651c0b2f7Stbbdev // regression test: certain MSVC runtime functions use "public" allocation functions
31751c0b2f7Stbbdev // but internal free routines, causing crashes if tbbmalloc_proxy does not intercept the latter.
31851c0b2f7Stbbdev void TestRuntimeRoutines() {
31951c0b2f7Stbbdev     system("rem should be a safe command to call");
32051c0b2f7Stbbdev }
32151c0b2f7Stbbdev #else
32251c0b2f7Stbbdev #define TestRuntimeRoutines()
32351c0b2f7Stbbdev #endif
32451c0b2f7Stbbdev 
32551c0b2f7Stbbdev struct BigStruct {
32651c0b2f7Stbbdev     char f[minLargeObjectSize];
32751c0b2f7Stbbdev };
32851c0b2f7Stbbdev 
32951c0b2f7Stbbdev void CheckNewDeleteOverload() {
330*478de5b1Stbbdev     BigStruct *s1, *s2, *s3, *s4, *s5, *s6;
33151c0b2f7Stbbdev 
33251c0b2f7Stbbdev     s1 = new BigStruct;
33351c0b2f7Stbbdev     scalableMallocCheckSize(s1, sizeof(BigStruct));
33451c0b2f7Stbbdev     delete s1;
33551c0b2f7Stbbdev 
33651c0b2f7Stbbdev     s2 = new BigStruct[10];
33751c0b2f7Stbbdev     scalableMallocCheckSize(s2, 10*sizeof(BigStruct));
33851c0b2f7Stbbdev     delete []s2;
33951c0b2f7Stbbdev 
34051c0b2f7Stbbdev     s3 = new(std::nothrow) BigStruct;
34151c0b2f7Stbbdev     scalableMallocCheckSize(s3, sizeof(BigStruct));
34251c0b2f7Stbbdev     delete s3;
34351c0b2f7Stbbdev 
34451c0b2f7Stbbdev     s4 = new(std::nothrow) BigStruct[2];
34551c0b2f7Stbbdev     scalableMallocCheckSize(s4, 2*sizeof(BigStruct));
34651c0b2f7Stbbdev     delete []s4;
347*478de5b1Stbbdev 
348*478de5b1Stbbdev     s5 = new BigStruct;
349*478de5b1Stbbdev     scalableMallocCheckSize(s5, sizeof(BigStruct));
350*478de5b1Stbbdev     operator delete(s5, std::nothrow);
351*478de5b1Stbbdev 
352*478de5b1Stbbdev     s6 = new BigStruct[5];
353*478de5b1Stbbdev     scalableMallocCheckSize(s6, 5*sizeof(BigStruct));
354*478de5b1Stbbdev     operator delete[](s6, std::nothrow);
355*478de5b1Stbbdev 
35651c0b2f7Stbbdev }
35751c0b2f7Stbbdev 
35851c0b2f7Stbbdev #if MALLOC_WINDOWS_OVERLOAD_ENABLED
35951c0b2f7Stbbdev void FuncReplacementInfoCheck() {
36051c0b2f7Stbbdev     char **func_replacement_log;
36151c0b2f7Stbbdev     int func_replacement_status = TBB_malloc_replacement_log(&func_replacement_log);
36251c0b2f7Stbbdev 
36351c0b2f7Stbbdev     std::set<std::string> functions;
36451c0b2f7Stbbdev     functions.insert("free");
36551c0b2f7Stbbdev     functions.insert("_msize");
36651c0b2f7Stbbdev     functions.insert("_aligned_free");
36751c0b2f7Stbbdev     functions.insert("_aligned_msize");
36851c0b2f7Stbbdev 
36951c0b2f7Stbbdev     int status_check = 0;
37051c0b2f7Stbbdev     for (char** log_string = func_replacement_log; *log_string != 0; log_string++) {
37151c0b2f7Stbbdev         std::stringstream s(*log_string);
37251c0b2f7Stbbdev         std::string status, function_name;
37351c0b2f7Stbbdev         s >> status >> function_name;
37451c0b2f7Stbbdev 
37551c0b2f7Stbbdev         if (status.find("Fail:") != status.npos) {
37651c0b2f7Stbbdev             status_check = -1;
37751c0b2f7Stbbdev         }
37851c0b2f7Stbbdev 
37951c0b2f7Stbbdev         functions.erase(function_name);
38051c0b2f7Stbbdev     }
38151c0b2f7Stbbdev 
38251c0b2f7Stbbdev     REQUIRE_MESSAGE(functions.empty(), "Changed opcodes log must contain all required functions with \"Success\" changed status");
38351c0b2f7Stbbdev     REQUIRE_MESSAGE(func_replacement_status == status_check, "replacement_opcodes_log() function return wrong status");
38451c0b2f7Stbbdev 
38551c0b2f7Stbbdev     func_replacement_status = TBB_malloc_replacement_log(NULL);
38651c0b2f7Stbbdev     REQUIRE_MESSAGE(func_replacement_status == status_check, "replacement_opcodes_log() function return wrong status");
38751c0b2f7Stbbdev 
38851c0b2f7Stbbdev     // TODO: was ASSERT_WARNING
38951c0b2f7Stbbdev     if (func_replacement_status != 0) {
39051c0b2f7Stbbdev         REPORT("Some standard allocation functions was not replaced to tbb_malloc functions.\n");
39151c0b2f7Stbbdev     }
39251c0b2f7Stbbdev }
39351c0b2f7Stbbdev #endif // MALLOC_WINDOWS_OVERLOAD_ENABLED
39451c0b2f7Stbbdev 
39551c0b2f7Stbbdev //! Testing tbbmalloc_proxy overload capabilities
39651c0b2f7Stbbdev //! \brief \ref error_guessing
39751c0b2f7Stbbdev TEST_CASE("Main set of tests") {
398*478de5b1Stbbdev #if __linux__
399*478de5b1Stbbdev     REQUIRE(mallopt(0, 0)); // add dummy mallopt call for coverage
400*478de5b1Stbbdev #endif // __linux__
401*478de5b1Stbbdev 
40251c0b2f7Stbbdev     void *ptr = NULL;
40351c0b2f7Stbbdev     utils::suppress_unused_warning(ptr); // for android
40451c0b2f7Stbbdev 
40551c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
40651c0b2f7Stbbdev     REQUIRE_MESSAGE(dlsym(RTLD_DEFAULT, "scalable_malloc"), "Lost dependency on malloc_proxy or LD_PRELOAD was not set?");
40751c0b2f7Stbbdev #endif
40851c0b2f7Stbbdev 
40951c0b2f7Stbbdev /* On Windows, memory block size returned by _msize() is sometimes used
41051c0b2f7Stbbdev    to calculate the size for an extended block. Substituting _msize,
41151c0b2f7Stbbdev    scalable_msize initially returned 0 for regions not allocated by the scalable
41251c0b2f7Stbbdev    allocator, which led to incorrect memory reallocation and subsequent crashes.
41351c0b2f7Stbbdev    It was found that adding a new environment variable triggers the error.
41451c0b2f7Stbbdev */
41551c0b2f7Stbbdev     REQUIRE_MESSAGE(getenv("PATH"), "We assume that PATH is set everywhere.");
41651c0b2f7Stbbdev     char *pathCopy = strdup(getenv("PATH"));
41751c0b2f7Stbbdev #if __ANDROID__
41851c0b2f7Stbbdev     REQUIRE_MESSAGE(strcmp(pathCopy,getenv("PATH")) == 0, "strdup workaround does not work as expected.");
41951c0b2f7Stbbdev #endif
42051c0b2f7Stbbdev     const char *newEnvName = "__TBBMALLOC_OVERLOAD_REGRESSION_TEST_FOR_REALLOC_AND_MSIZE";
42151c0b2f7Stbbdev     REQUIRE_MESSAGE(!getenv(newEnvName), "Environment variable should not be used before.");
42251c0b2f7Stbbdev     int r = utils::SetEnv(newEnvName,"1");
42351c0b2f7Stbbdev     REQUIRE(!r);
42451c0b2f7Stbbdev     char *path = getenv("PATH");
42551c0b2f7Stbbdev     REQUIRE_MESSAGE((path && 0==strcmp(path, pathCopy)), "Environment was changed erroneously.");
42651c0b2f7Stbbdev     free(pathCopy);
42751c0b2f7Stbbdev 
42851c0b2f7Stbbdev     CheckStdFuncOverload(malloc, calloc, realloc, free);
42951c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
43051c0b2f7Stbbdev 
43151c0b2f7Stbbdev #if __TBB_POSIX_MEMALIGN_PRESENT
43251c0b2f7Stbbdev     int ret = posix_memalign(&ptr, 1024, 3*minLargeObjectSize);
43351c0b2f7Stbbdev     REQUIRE(0 == ret);
43451c0b2f7Stbbdev     scalableMallocCheckSize(ptr, 3*minLargeObjectSize);
43551c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 1024));
43651c0b2f7Stbbdev     free(ptr);
43751c0b2f7Stbbdev #endif
43851c0b2f7Stbbdev 
43951c0b2f7Stbbdev #if __TBB_VALLOC_PRESENT
44051c0b2f7Stbbdev     CheckVallocFuncOverload(valloc, free);
44151c0b2f7Stbbdev #endif
44251c0b2f7Stbbdev #if __TBB_PVALLOC_PRESENT
44351c0b2f7Stbbdev     CheckPvalloc(pvalloc, free);
44451c0b2f7Stbbdev #endif
44551c0b2f7Stbbdev #if __linux__
44651c0b2f7Stbbdev     CheckMemalignFuncOverload(memalign, free);
44751c0b2f7Stbbdev #if __TBB_ALIGNED_ALLOC_PRESENT
44851c0b2f7Stbbdev     CheckMemalignFuncOverload(aligned_alloc, free);
44951c0b2f7Stbbdev #endif
45051c0b2f7Stbbdev 
45151c0b2f7Stbbdev     struct mallinfo info = mallinfo();
45251c0b2f7Stbbdev     // right now mallinfo initialized by zero
45351c0b2f7Stbbdev     REQUIRE((!info.arena && !info.ordblks && !info.smblks && !info.hblks
45451c0b2f7Stbbdev            && !info.hblkhd && !info.usmblks && !info.fsmblks
45551c0b2f7Stbbdev            && !info.uordblks && !info.fordblks && !info.keepcost));
45651c0b2f7Stbbdev 
45751c0b2f7Stbbdev  #if !__ANDROID__
45851c0b2f7Stbbdev     // These non-standard functions are exported by GLIBC, and might be used
45951c0b2f7Stbbdev     // in conjunction with standard malloc/free. Test that we overload them as well.
46051c0b2f7Stbbdev     // Bionic doesn't have them.
46151c0b2f7Stbbdev     CheckStdFuncOverload(__libc_malloc, __libc_calloc, __libc_realloc, __libc_free);
46251c0b2f7Stbbdev     CheckMemalignFuncOverload(__libc_memalign, __libc_free);
46351c0b2f7Stbbdev     CheckVallocFuncOverload(__libc_valloc, __libc_free);
46451c0b2f7Stbbdev     CheckPvalloc(__libc_pvalloc, __libc_free);
46551c0b2f7Stbbdev  #endif
46651c0b2f7Stbbdev #endif // __linux__
46751c0b2f7Stbbdev 
46851c0b2f7Stbbdev #else // MALLOC_WINDOWS_OVERLOAD_ENABLED
46951c0b2f7Stbbdev 
47051c0b2f7Stbbdev     ptr = _aligned_malloc(minLargeObjectSize, 16);
47151c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
47251c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 16));
47351c0b2f7Stbbdev 
47451c0b2f7Stbbdev     // Testing of workaround for vs "is power of 2 pow N" bug that accepts zeros
47551c0b2f7Stbbdev     void* ptr1 = _aligned_malloc(minLargeObjectSize, 0);
47651c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
47751c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, sizeof(void*)));
47851c0b2f7Stbbdev     _aligned_free(ptr1);
47951c0b2f7Stbbdev 
48051c0b2f7Stbbdev     ptr1 = _aligned_realloc(ptr, minLargeObjectSize*10, 16);
48151c0b2f7Stbbdev     scalableMallocCheckSize(ptr1, minLargeObjectSize*10);
48251c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 16));
48351c0b2f7Stbbdev     _aligned_free(ptr1);
48451c0b2f7Stbbdev 
48551c0b2f7Stbbdev     FuncReplacementInfoCheck();
48651c0b2f7Stbbdev 
48751c0b2f7Stbbdev #endif
48851c0b2f7Stbbdev     CheckFreeAligned();
48951c0b2f7Stbbdev 
49051c0b2f7Stbbdev     CheckNewDeleteOverload();
49151c0b2f7Stbbdev 
49251c0b2f7Stbbdev #if _WIN32
49351c0b2f7Stbbdev     std::string stdstring = "dependency on msvcpXX.dll";
49451c0b2f7Stbbdev     REQUIRE(strcmp(stdstring.c_str(), "dependency on msvcpXX.dll") == 0);
49551c0b2f7Stbbdev #endif
49651c0b2f7Stbbdev     TestZoneOverload();
49751c0b2f7Stbbdev     TestRuntimeRoutines();
49851c0b2f7Stbbdev }
49951c0b2f7Stbbdev #endif // !HARNESS_SKIP_TEST
500