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