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