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