1*51c0b2f7Stbbdev /* 2*51c0b2f7Stbbdev Copyright (c) 2005-2020 Intel Corporation 3*51c0b2f7Stbbdev 4*51c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 5*51c0b2f7Stbbdev you may not use this file except in compliance with the License. 6*51c0b2f7Stbbdev You may obtain a copy of the License at 7*51c0b2f7Stbbdev 8*51c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 9*51c0b2f7Stbbdev 10*51c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 11*51c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 12*51c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*51c0b2f7Stbbdev See the License for the specific language governing permissions and 14*51c0b2f7Stbbdev limitations under the License. 15*51c0b2f7Stbbdev */ 16*51c0b2f7Stbbdev 17*51c0b2f7Stbbdev //! \file test_malloc_overload.cpp 18*51c0b2f7Stbbdev //! \brief Test for [memory_allocation] functionality 19*51c0b2f7Stbbdev 20*51c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1 21*51c0b2f7Stbbdev 22*51c0b2f7Stbbdev #if (_WIN32 || _WIN64) 23*51c0b2f7Stbbdev // As the test is intentionally build with /EHs-, suppress multiple VS2005's 24*51c0b2f7Stbbdev // warnings like C4530: C++ exception handler used, but unwind semantics are not enabled 25*51c0b2f7Stbbdev #if defined(_MSC_VER) && !__INTEL_COMPILER 26*51c0b2f7Stbbdev /* ICC 10.1 and 11.0 generates code that uses std::_Raise_handler, 27*51c0b2f7Stbbdev but it's only defined in libcpmt(d), which the test doesn't linked with. 28*51c0b2f7Stbbdev */ 29*51c0b2f7Stbbdev #undef _HAS_EXCEPTIONS 30*51c0b2f7Stbbdev #define _HAS_EXCEPTIONS _CPPUNWIND 31*51c0b2f7Stbbdev #endif 32*51c0b2f7Stbbdev // to use strdup w/o warnings 33*51c0b2f7Stbbdev #define _CRT_NONSTDC_NO_DEPRECATE 1 34*51c0b2f7Stbbdev #endif // _WIN32 || _WIN64 35*51c0b2f7Stbbdev 36*51c0b2f7Stbbdev #define _ISOC11_SOURCE 1 // to get C11 declarations for GLIBC 37*51c0b2f7Stbbdev 38*51c0b2f7Stbbdev #include "common/allocator_overload.h" 39*51c0b2f7Stbbdev 40*51c0b2f7Stbbdev #if MALLOC_WINDOWS_OVERLOAD_ENABLED 41*51c0b2f7Stbbdev #include "tbb/tbbmalloc_proxy.h" 42*51c0b2f7Stbbdev #endif 43*51c0b2f7Stbbdev 44*51c0b2f7Stbbdev #include "common/test.h" 45*51c0b2f7Stbbdev 46*51c0b2f7Stbbdev #if !HARNESS_SKIP_TEST 47*51c0b2f7Stbbdev 48*51c0b2f7Stbbdev #if __ANDROID__ 49*51c0b2f7Stbbdev #include <android/api-level.h> // for __ANDROID_API__ 50*51c0b2f7Stbbdev #endif 51*51c0b2f7Stbbdev 52*51c0b2f7Stbbdev #define __TBB_POSIX_MEMALIGN_PRESENT (__linux__ && !__ANDROID__) || __APPLE__ 53*51c0b2f7Stbbdev #define __TBB_PVALLOC_PRESENT __linux__ && !__ANDROID__ 54*51c0b2f7Stbbdev #if __GLIBC__ 55*51c0b2f7Stbbdev // aligned_alloc available since GLIBC 2.16 56*51c0b2f7Stbbdev #define __TBB_ALIGNED_ALLOC_PRESENT __GLIBC_PREREQ(2, 16) 57*51c0b2f7Stbbdev #endif // __GLIBC__ 58*51c0b2f7Stbbdev // later Android doesn't have valloc or dlmalloc_usable_size 59*51c0b2f7Stbbdev #define __TBB_VALLOC_PRESENT (__linux__ && __ANDROID_API__<21) || __APPLE__ 60*51c0b2f7Stbbdev #define __TBB_DLMALLOC_USABLE_SIZE_PRESENT __ANDROID__ && __ANDROID_API__<21 61*51c0b2f7Stbbdev 62*51c0b2f7Stbbdev #include "common/utils.h" 63*51c0b2f7Stbbdev #include "common/utils_report.h" 64*51c0b2f7Stbbdev #include "common/utils_assert.h" 65*51c0b2f7Stbbdev #include "common/utils_env.h" 66*51c0b2f7Stbbdev 67*51c0b2f7Stbbdev #include <stdlib.h> 68*51c0b2f7Stbbdev #include <string.h> 69*51c0b2f7Stbbdev #if !__APPLE__ 70*51c0b2f7Stbbdev #include <malloc.h> 71*51c0b2f7Stbbdev #endif 72*51c0b2f7Stbbdev #include <stdio.h> 73*51c0b2f7Stbbdev #include <new> 74*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 75*51c0b2f7Stbbdev #include <unistd.h> // for sysconf 76*51c0b2f7Stbbdev #include <dlfcn.h> 77*51c0b2f7Stbbdev #endif 78*51c0b2f7Stbbdev 79*51c0b2f7Stbbdev #if __linux__ 80*51c0b2f7Stbbdev #include <stdint.h> // for uintptr_t 81*51c0b2f7Stbbdev 82*51c0b2f7Stbbdev extern "C" { 83*51c0b2f7Stbbdev void *__libc_malloc(size_t size); 84*51c0b2f7Stbbdev void *__libc_realloc(void *ptr, size_t size); 85*51c0b2f7Stbbdev void *__libc_calloc(size_t num, size_t size); 86*51c0b2f7Stbbdev void __libc_free(void *ptr); 87*51c0b2f7Stbbdev void *__libc_memalign(size_t alignment, size_t size); 88*51c0b2f7Stbbdev void *__libc_pvalloc(size_t size); 89*51c0b2f7Stbbdev void *__libc_valloc(size_t size); 90*51c0b2f7Stbbdev #if __TBB_DLMALLOC_USABLE_SIZE_PRESENT 91*51c0b2f7Stbbdev #define malloc_usable_size(p) dlmalloc_usable_size(p) 92*51c0b2f7Stbbdev size_t dlmalloc_usable_size(const void *ptr); 93*51c0b2f7Stbbdev #endif 94*51c0b2f7Stbbdev } 95*51c0b2f7Stbbdev 96*51c0b2f7Stbbdev #elif __APPLE__ 97*51c0b2f7Stbbdev 98*51c0b2f7Stbbdev #include <malloc/malloc.h> 99*51c0b2f7Stbbdev #define malloc_usable_size(p) malloc_size(p) 100*51c0b2f7Stbbdev 101*51c0b2f7Stbbdev #elif _WIN32 102*51c0b2f7Stbbdev #include <stddef.h> 103*51c0b2f7Stbbdev #if __MINGW32__ 104*51c0b2f7Stbbdev #include <unistd.h> 105*51c0b2f7Stbbdev #else 106*51c0b2f7Stbbdev typedef unsigned __int16 uint16_t; 107*51c0b2f7Stbbdev typedef unsigned __int32 uint32_t; 108*51c0b2f7Stbbdev typedef unsigned __int64 uint64_t; 109*51c0b2f7Stbbdev #endif 110*51c0b2f7Stbbdev 111*51c0b2f7Stbbdev #endif /* OS selection */ 112*51c0b2f7Stbbdev 113*51c0b2f7Stbbdev #if _WIN32 114*51c0b2f7Stbbdev // On Windows, the trick with string "dependency on msvcpXX.dll" is necessary to create 115*51c0b2f7Stbbdev // dependency on msvcpXX.dll, for sake of a regression test. 116*51c0b2f7Stbbdev // On Linux, C++ RTL headers are undesirable because of breaking strict ANSI mode. 117*51c0b2f7Stbbdev #if defined(_MSC_VER) && _MSC_VER >= 1300 && _MSC_VER <= 1310 && !defined(__INTEL_COMPILER) 118*51c0b2f7Stbbdev /* Fixing compilation error reported by VS2003 for exception class 119*51c0b2f7Stbbdev when _HAS_EXCEPTIONS is 0: 120*51c0b2f7Stbbdev bad_cast that inherited from exception is not in std namespace. 121*51c0b2f7Stbbdev */ 122*51c0b2f7Stbbdev using namespace std; 123*51c0b2f7Stbbdev #endif 124*51c0b2f7Stbbdev #include <string> 125*51c0b2f7Stbbdev #include <set> 126*51c0b2f7Stbbdev #include <sstream> 127*51c0b2f7Stbbdev #endif 128*51c0b2f7Stbbdev 129*51c0b2f7Stbbdev #include "tbb/detail/_utils.h" // tbb::detail::is_aligned 130*51c0b2f7Stbbdev #include "src/tbbmalloc/shared_utils.h" // alignDown, alignUp, estimatedCacheLineSize 131*51c0b2f7Stbbdev 132*51c0b2f7Stbbdev /* start of code replicated from src/tbbmalloc */ 133*51c0b2f7Stbbdev 134*51c0b2f7Stbbdev class BackRefIdx { // composite index to backreference array 135*51c0b2f7Stbbdev private: 136*51c0b2f7Stbbdev uint16_t master; // index in BackRefMaster 137*51c0b2f7Stbbdev uint16_t largeObj:1; // is this object "large"? 138*51c0b2f7Stbbdev uint16_t offset :15; // offset from beginning of BackRefBlock 139*51c0b2f7Stbbdev public: 140*51c0b2f7Stbbdev BackRefIdx() : master((uint16_t)-1) {} 141*51c0b2f7Stbbdev bool isInvalid() { return master == (uint16_t)-1; } 142*51c0b2f7Stbbdev bool isLargeObject() const { return largeObj; } 143*51c0b2f7Stbbdev uint16_t getMaster() const { return master; } 144*51c0b2f7Stbbdev uint16_t getOffset() const { return offset; } 145*51c0b2f7Stbbdev 146*51c0b2f7Stbbdev // only newBackRef can modify BackRefIdx 147*51c0b2f7Stbbdev static BackRefIdx newBackRef(bool largeObj); 148*51c0b2f7Stbbdev }; 149*51c0b2f7Stbbdev 150*51c0b2f7Stbbdev class MemoryPool; 151*51c0b2f7Stbbdev class ExtMemoryPool; 152*51c0b2f7Stbbdev 153*51c0b2f7Stbbdev struct BlockI { 154*51c0b2f7Stbbdev intptr_t blockState[2]; 155*51c0b2f7Stbbdev }; 156*51c0b2f7Stbbdev 157*51c0b2f7Stbbdev struct LargeMemoryBlock : public BlockI { 158*51c0b2f7Stbbdev MemoryPool *pool; // owner pool 159*51c0b2f7Stbbdev LargeMemoryBlock *next, // ptrs in list of cached blocks 160*51c0b2f7Stbbdev *prev, 161*51c0b2f7Stbbdev *gPrev, // in pool's global list 162*51c0b2f7Stbbdev *gNext; 163*51c0b2f7Stbbdev uintptr_t age; // age of block while in cache 164*51c0b2f7Stbbdev size_t objectSize; // the size requested by a client 165*51c0b2f7Stbbdev size_t unalignedSize; // the size requested from getMemory 166*51c0b2f7Stbbdev bool fromMapMemory; 167*51c0b2f7Stbbdev BackRefIdx backRefIdx; // cached here, used copy is in LargeObjectHdr 168*51c0b2f7Stbbdev void registerInPool(ExtMemoryPool *extMemPool); 169*51c0b2f7Stbbdev void unregisterFromPool(ExtMemoryPool *extMemPool); 170*51c0b2f7Stbbdev }; 171*51c0b2f7Stbbdev 172*51c0b2f7Stbbdev struct LargeObjectHdr { 173*51c0b2f7Stbbdev LargeMemoryBlock *memoryBlock; 174*51c0b2f7Stbbdev /* Have to duplicate it here from CachedObjectHdr, 175*51c0b2f7Stbbdev as backreference must be checked without further pointer dereference. 176*51c0b2f7Stbbdev Points to LargeObjectHdr. */ 177*51c0b2f7Stbbdev BackRefIdx backRefIdx; 178*51c0b2f7Stbbdev }; 179*51c0b2f7Stbbdev 180*51c0b2f7Stbbdev /* 181*51c0b2f7Stbbdev * Objects of size minLargeObjectSize and larger are considered large objects. 182*51c0b2f7Stbbdev */ 183*51c0b2f7Stbbdev const uintptr_t blockSize = 16*1024; 184*51c0b2f7Stbbdev const uint32_t fittingAlignment = rml::internal::estimatedCacheLineSize; 185*51c0b2f7Stbbdev #define SET_FITTING_SIZE(N) ( (blockSize-2*rml::internal::estimatedCacheLineSize)/N ) & ~(fittingAlignment-1) 186*51c0b2f7Stbbdev const uint32_t fittingSize5 = SET_FITTING_SIZE(2); // 8128/8064 187*51c0b2f7Stbbdev #undef SET_FITTING_SIZE 188*51c0b2f7Stbbdev const uint32_t minLargeObjectSize = fittingSize5 + 1; 189*51c0b2f7Stbbdev 190*51c0b2f7Stbbdev /* end of code replicated from src/tbbmalloc */ 191*51c0b2f7Stbbdev 192*51c0b2f7Stbbdev static void scalableMallocCheckSize(void *object, size_t size) 193*51c0b2f7Stbbdev { 194*51c0b2f7Stbbdev #if __clang__ 195*51c0b2f7Stbbdev // This prevents Clang from throwing out the calls to new & delete in CheckNewDeleteOverload(). 196*51c0b2f7Stbbdev static void *v = object; 197*51c0b2f7Stbbdev utils::suppress_unused_warning(v); 198*51c0b2f7Stbbdev #endif 199*51c0b2f7Stbbdev REQUIRE(object); 200*51c0b2f7Stbbdev if (size >= minLargeObjectSize) { 201*51c0b2f7Stbbdev LargeMemoryBlock *lmb = ((LargeObjectHdr*)object-1)->memoryBlock; 202*51c0b2f7Stbbdev REQUIRE((uintptr_t(lmb)<uintptr_t(((LargeObjectHdr*)object-1)) && lmb->objectSize >= size)); 203*51c0b2f7Stbbdev } 204*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 205*51c0b2f7Stbbdev REQUIRE(malloc_usable_size(object) >= size); 206*51c0b2f7Stbbdev #elif MALLOC_WINDOWS_OVERLOAD_ENABLED 207*51c0b2f7Stbbdev // Check that _msize works correctly 208*51c0b2f7Stbbdev REQUIRE(_msize(object) >= size); 209*51c0b2f7Stbbdev REQUIRE((size < 8 || _aligned_msize(object,8,0) >= size)); 210*51c0b2f7Stbbdev #endif 211*51c0b2f7Stbbdev } 212*51c0b2f7Stbbdev 213*51c0b2f7Stbbdev void CheckStdFuncOverload(void *(*malloc_p)(size_t), void *(*calloc_p)(size_t, size_t), 214*51c0b2f7Stbbdev void *(*realloc_p)(void *, size_t), void (*free_p)(void *)) 215*51c0b2f7Stbbdev { 216*51c0b2f7Stbbdev void *ptr = malloc_p(minLargeObjectSize); 217*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, minLargeObjectSize); 218*51c0b2f7Stbbdev free(ptr); 219*51c0b2f7Stbbdev 220*51c0b2f7Stbbdev ptr = calloc_p(minLargeObjectSize, 2); 221*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, 2*minLargeObjectSize); 222*51c0b2f7Stbbdev void *ptr1 = realloc_p(ptr, 10*minLargeObjectSize); 223*51c0b2f7Stbbdev scalableMallocCheckSize(ptr1, 10*minLargeObjectSize); 224*51c0b2f7Stbbdev free_p(ptr1); 225*51c0b2f7Stbbdev } 226*51c0b2f7Stbbdev 227*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 228*51c0b2f7Stbbdev 229*51c0b2f7Stbbdev void CheckMemalignFuncOverload(void *(*memalign_p)(size_t, size_t), 230*51c0b2f7Stbbdev void (*free_p)(void*)) 231*51c0b2f7Stbbdev { 232*51c0b2f7Stbbdev void *ptr = memalign_p(128, 4*minLargeObjectSize); 233*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, 4*minLargeObjectSize); 234*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, 128)); 235*51c0b2f7Stbbdev free_p(ptr); 236*51c0b2f7Stbbdev } 237*51c0b2f7Stbbdev 238*51c0b2f7Stbbdev void CheckVallocFuncOverload(void *(*valloc_p)(size_t), void (*free_p)(void*)) 239*51c0b2f7Stbbdev { 240*51c0b2f7Stbbdev void *ptr = valloc_p(minLargeObjectSize); 241*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, minLargeObjectSize); 242*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, sysconf(_SC_PAGESIZE))); 243*51c0b2f7Stbbdev free_p(ptr); 244*51c0b2f7Stbbdev } 245*51c0b2f7Stbbdev 246*51c0b2f7Stbbdev void CheckPvalloc(void *(*pvalloc_p)(size_t), void (*free_p)(void*)) 247*51c0b2f7Stbbdev { 248*51c0b2f7Stbbdev const long memoryPageSize = sysconf(_SC_PAGESIZE); 249*51c0b2f7Stbbdev // request large object with not power-of-2 size 250*51c0b2f7Stbbdev const size_t largeSz = alignUp(minLargeObjectSize, 16*1024) + 1; 251*51c0b2f7Stbbdev 252*51c0b2f7Stbbdev for (size_t sz = 0; sz<=largeSz; sz+=largeSz) { 253*51c0b2f7Stbbdev void *ptr = pvalloc_p(sz); 254*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, sz? alignUp(sz, memoryPageSize) : memoryPageSize); 255*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, memoryPageSize)); 256*51c0b2f7Stbbdev free_p(ptr); 257*51c0b2f7Stbbdev } 258*51c0b2f7Stbbdev } 259*51c0b2f7Stbbdev 260*51c0b2f7Stbbdev #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 261*51c0b2f7Stbbdev 262*51c0b2f7Stbbdev // regression test: on macOS scalable_free() treated small aligned object, 263*51c0b2f7Stbbdev // placed in large block, as small block 264*51c0b2f7Stbbdev void CheckFreeAligned() { 265*51c0b2f7Stbbdev size_t sz[] = {8, 4*1024, 16*1024, 0}; 266*51c0b2f7Stbbdev size_t align[] = {8, 4*1024, 16*1024, 0}; 267*51c0b2f7Stbbdev 268*51c0b2f7Stbbdev for (int s=0; sz[s]; s++) 269*51c0b2f7Stbbdev for (int a=0; align[a]; a++) { 270*51c0b2f7Stbbdev void *ptr = NULL; 271*51c0b2f7Stbbdev #if __TBB_POSIX_MEMALIGN_PRESENT 272*51c0b2f7Stbbdev int ret = posix_memalign(&ptr, align[a], sz[s]); 273*51c0b2f7Stbbdev REQUIRE(!ret); 274*51c0b2f7Stbbdev #elif MALLOC_WINDOWS_OVERLOAD_ENABLED 275*51c0b2f7Stbbdev ptr = _aligned_malloc(sz[s], align[a]); 276*51c0b2f7Stbbdev #endif 277*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, align[a])); 278*51c0b2f7Stbbdev free(ptr); 279*51c0b2f7Stbbdev } 280*51c0b2f7Stbbdev } 281*51c0b2f7Stbbdev 282*51c0b2f7Stbbdev #if __ANDROID__ 283*51c0b2f7Stbbdev // Workaround for an issue with strdup somehow bypassing our malloc replacement on Android. 284*51c0b2f7Stbbdev char *strdup(const char *str) { 285*51c0b2f7Stbbdev REPORT( "Known issue: malloc replacement does not work for strdup on Android.\n" ); 286*51c0b2f7Stbbdev size_t len = strlen(str)+1; 287*51c0b2f7Stbbdev void *new_str = malloc(len); 288*51c0b2f7Stbbdev return new_str ? reinterpret_cast<char *>(memcpy(new_str, str, len)) : 0; 289*51c0b2f7Stbbdev } 290*51c0b2f7Stbbdev #endif 291*51c0b2f7Stbbdev 292*51c0b2f7Stbbdev #if __APPLE__ 293*51c0b2f7Stbbdev #include <mach/mach.h> 294*51c0b2f7Stbbdev 295*51c0b2f7Stbbdev // regression test: malloc_usable_size() that was passed to zone interface 296*51c0b2f7Stbbdev // called system malloc_usable_size(), so for object that was not allocated 297*51c0b2f7Stbbdev // by tbbmalloc non-zero was returned, so such objects were passed to 298*51c0b2f7Stbbdev // tbbmalloc's free(), that is incorrect 299*51c0b2f7Stbbdev void TestZoneOverload() { 300*51c0b2f7Stbbdev vm_address_t *zones; 301*51c0b2f7Stbbdev unsigned zones_num; 302*51c0b2f7Stbbdev 303*51c0b2f7Stbbdev kern_return_t ret = malloc_get_all_zones(mach_task_self(), NULL, &zones, &zones_num); 304*51c0b2f7Stbbdev REQUIRE((!ret && zones_num>1)); 305*51c0b2f7Stbbdev malloc_zone_t *sys_zone = (malloc_zone_t*)zones[1]; 306*51c0b2f7Stbbdev REQUIRE_MESSAGE(strcmp("tbbmalloc", malloc_get_zone_name(sys_zone)), "zone 1 expected to be not tbbmalloc"); 307*51c0b2f7Stbbdev void *p = malloc_zone_malloc(sys_zone, 16); 308*51c0b2f7Stbbdev free(p); 309*51c0b2f7Stbbdev } 310*51c0b2f7Stbbdev #else 311*51c0b2f7Stbbdev #define TestZoneOverload() 312*51c0b2f7Stbbdev #endif 313*51c0b2f7Stbbdev 314*51c0b2f7Stbbdev #if _WIN32 315*51c0b2f7Stbbdev // regression test: certain MSVC runtime functions use "public" allocation functions 316*51c0b2f7Stbbdev // but internal free routines, causing crashes if tbbmalloc_proxy does not intercept the latter. 317*51c0b2f7Stbbdev void TestRuntimeRoutines() { 318*51c0b2f7Stbbdev system("rem should be a safe command to call"); 319*51c0b2f7Stbbdev } 320*51c0b2f7Stbbdev #else 321*51c0b2f7Stbbdev #define TestRuntimeRoutines() 322*51c0b2f7Stbbdev #endif 323*51c0b2f7Stbbdev 324*51c0b2f7Stbbdev struct BigStruct { 325*51c0b2f7Stbbdev char f[minLargeObjectSize]; 326*51c0b2f7Stbbdev }; 327*51c0b2f7Stbbdev 328*51c0b2f7Stbbdev void CheckNewDeleteOverload() { 329*51c0b2f7Stbbdev BigStruct *s1, *s2, *s3, *s4; 330*51c0b2f7Stbbdev 331*51c0b2f7Stbbdev s1 = new BigStruct; 332*51c0b2f7Stbbdev scalableMallocCheckSize(s1, sizeof(BigStruct)); 333*51c0b2f7Stbbdev delete s1; 334*51c0b2f7Stbbdev 335*51c0b2f7Stbbdev s2 = new BigStruct[10]; 336*51c0b2f7Stbbdev scalableMallocCheckSize(s2, 10*sizeof(BigStruct)); 337*51c0b2f7Stbbdev delete []s2; 338*51c0b2f7Stbbdev 339*51c0b2f7Stbbdev s3 = new(std::nothrow) BigStruct; 340*51c0b2f7Stbbdev scalableMallocCheckSize(s3, sizeof(BigStruct)); 341*51c0b2f7Stbbdev delete s3; 342*51c0b2f7Stbbdev 343*51c0b2f7Stbbdev s4 = new(std::nothrow) BigStruct[2]; 344*51c0b2f7Stbbdev scalableMallocCheckSize(s4, 2*sizeof(BigStruct)); 345*51c0b2f7Stbbdev delete []s4; 346*51c0b2f7Stbbdev } 347*51c0b2f7Stbbdev 348*51c0b2f7Stbbdev #if MALLOC_WINDOWS_OVERLOAD_ENABLED 349*51c0b2f7Stbbdev void FuncReplacementInfoCheck() { 350*51c0b2f7Stbbdev char **func_replacement_log; 351*51c0b2f7Stbbdev int func_replacement_status = TBB_malloc_replacement_log(&func_replacement_log); 352*51c0b2f7Stbbdev 353*51c0b2f7Stbbdev std::set<std::string> functions; 354*51c0b2f7Stbbdev functions.insert("free"); 355*51c0b2f7Stbbdev functions.insert("_msize"); 356*51c0b2f7Stbbdev functions.insert("_aligned_free"); 357*51c0b2f7Stbbdev functions.insert("_aligned_msize"); 358*51c0b2f7Stbbdev 359*51c0b2f7Stbbdev int status_check = 0; 360*51c0b2f7Stbbdev for (char** log_string = func_replacement_log; *log_string != 0; log_string++) { 361*51c0b2f7Stbbdev std::stringstream s(*log_string); 362*51c0b2f7Stbbdev std::string status, function_name; 363*51c0b2f7Stbbdev s >> status >> function_name; 364*51c0b2f7Stbbdev 365*51c0b2f7Stbbdev if (status.find("Fail:") != status.npos) { 366*51c0b2f7Stbbdev status_check = -1; 367*51c0b2f7Stbbdev } 368*51c0b2f7Stbbdev 369*51c0b2f7Stbbdev functions.erase(function_name); 370*51c0b2f7Stbbdev } 371*51c0b2f7Stbbdev 372*51c0b2f7Stbbdev REQUIRE_MESSAGE(functions.empty(), "Changed opcodes log must contain all required functions with \"Success\" changed status"); 373*51c0b2f7Stbbdev REQUIRE_MESSAGE(func_replacement_status == status_check, "replacement_opcodes_log() function return wrong status"); 374*51c0b2f7Stbbdev 375*51c0b2f7Stbbdev func_replacement_status = TBB_malloc_replacement_log(NULL); 376*51c0b2f7Stbbdev REQUIRE_MESSAGE(func_replacement_status == status_check, "replacement_opcodes_log() function return wrong status"); 377*51c0b2f7Stbbdev 378*51c0b2f7Stbbdev // TODO: was ASSERT_WARNING 379*51c0b2f7Stbbdev if (func_replacement_status != 0) { 380*51c0b2f7Stbbdev REPORT("Some standard allocation functions was not replaced to tbb_malloc functions.\n"); 381*51c0b2f7Stbbdev } 382*51c0b2f7Stbbdev } 383*51c0b2f7Stbbdev #endif // MALLOC_WINDOWS_OVERLOAD_ENABLED 384*51c0b2f7Stbbdev 385*51c0b2f7Stbbdev //! Testing tbbmalloc_proxy overload capabilities 386*51c0b2f7Stbbdev //! \brief \ref error_guessing 387*51c0b2f7Stbbdev TEST_CASE("Main set of tests") { 388*51c0b2f7Stbbdev void *ptr = NULL; 389*51c0b2f7Stbbdev utils::suppress_unused_warning(ptr); // for android 390*51c0b2f7Stbbdev 391*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 392*51c0b2f7Stbbdev REQUIRE_MESSAGE(dlsym(RTLD_DEFAULT, "scalable_malloc"), "Lost dependency on malloc_proxy or LD_PRELOAD was not set?"); 393*51c0b2f7Stbbdev #endif 394*51c0b2f7Stbbdev 395*51c0b2f7Stbbdev /* On Windows, memory block size returned by _msize() is sometimes used 396*51c0b2f7Stbbdev to calculate the size for an extended block. Substituting _msize, 397*51c0b2f7Stbbdev scalable_msize initially returned 0 for regions not allocated by the scalable 398*51c0b2f7Stbbdev allocator, which led to incorrect memory reallocation and subsequent crashes. 399*51c0b2f7Stbbdev It was found that adding a new environment variable triggers the error. 400*51c0b2f7Stbbdev */ 401*51c0b2f7Stbbdev REQUIRE_MESSAGE(getenv("PATH"), "We assume that PATH is set everywhere."); 402*51c0b2f7Stbbdev char *pathCopy = strdup(getenv("PATH")); 403*51c0b2f7Stbbdev #if __ANDROID__ 404*51c0b2f7Stbbdev REQUIRE_MESSAGE(strcmp(pathCopy,getenv("PATH")) == 0, "strdup workaround does not work as expected."); 405*51c0b2f7Stbbdev #endif 406*51c0b2f7Stbbdev const char *newEnvName = "__TBBMALLOC_OVERLOAD_REGRESSION_TEST_FOR_REALLOC_AND_MSIZE"; 407*51c0b2f7Stbbdev REQUIRE_MESSAGE(!getenv(newEnvName), "Environment variable should not be used before."); 408*51c0b2f7Stbbdev int r = utils::SetEnv(newEnvName,"1"); 409*51c0b2f7Stbbdev REQUIRE(!r); 410*51c0b2f7Stbbdev char *path = getenv("PATH"); 411*51c0b2f7Stbbdev REQUIRE_MESSAGE((path && 0==strcmp(path, pathCopy)), "Environment was changed erroneously."); 412*51c0b2f7Stbbdev free(pathCopy); 413*51c0b2f7Stbbdev 414*51c0b2f7Stbbdev CheckStdFuncOverload(malloc, calloc, realloc, free); 415*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 416*51c0b2f7Stbbdev 417*51c0b2f7Stbbdev #if __TBB_POSIX_MEMALIGN_PRESENT 418*51c0b2f7Stbbdev int ret = posix_memalign(&ptr, 1024, 3*minLargeObjectSize); 419*51c0b2f7Stbbdev REQUIRE(0 == ret); 420*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, 3*minLargeObjectSize); 421*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, 1024)); 422*51c0b2f7Stbbdev free(ptr); 423*51c0b2f7Stbbdev #endif 424*51c0b2f7Stbbdev 425*51c0b2f7Stbbdev #if __TBB_VALLOC_PRESENT 426*51c0b2f7Stbbdev CheckVallocFuncOverload(valloc, free); 427*51c0b2f7Stbbdev #endif 428*51c0b2f7Stbbdev #if __TBB_PVALLOC_PRESENT 429*51c0b2f7Stbbdev CheckPvalloc(pvalloc, free); 430*51c0b2f7Stbbdev #endif 431*51c0b2f7Stbbdev #if __linux__ 432*51c0b2f7Stbbdev CheckMemalignFuncOverload(memalign, free); 433*51c0b2f7Stbbdev #if __TBB_ALIGNED_ALLOC_PRESENT 434*51c0b2f7Stbbdev CheckMemalignFuncOverload(aligned_alloc, free); 435*51c0b2f7Stbbdev #endif 436*51c0b2f7Stbbdev 437*51c0b2f7Stbbdev struct mallinfo info = mallinfo(); 438*51c0b2f7Stbbdev // right now mallinfo initialized by zero 439*51c0b2f7Stbbdev REQUIRE((!info.arena && !info.ordblks && !info.smblks && !info.hblks 440*51c0b2f7Stbbdev && !info.hblkhd && !info.usmblks && !info.fsmblks 441*51c0b2f7Stbbdev && !info.uordblks && !info.fordblks && !info.keepcost)); 442*51c0b2f7Stbbdev 443*51c0b2f7Stbbdev #if !__ANDROID__ 444*51c0b2f7Stbbdev // These non-standard functions are exported by GLIBC, and might be used 445*51c0b2f7Stbbdev // in conjunction with standard malloc/free. Test that we overload them as well. 446*51c0b2f7Stbbdev // Bionic doesn't have them. 447*51c0b2f7Stbbdev CheckStdFuncOverload(__libc_malloc, __libc_calloc, __libc_realloc, __libc_free); 448*51c0b2f7Stbbdev CheckMemalignFuncOverload(__libc_memalign, __libc_free); 449*51c0b2f7Stbbdev CheckVallocFuncOverload(__libc_valloc, __libc_free); 450*51c0b2f7Stbbdev CheckPvalloc(__libc_pvalloc, __libc_free); 451*51c0b2f7Stbbdev #endif 452*51c0b2f7Stbbdev #endif // __linux__ 453*51c0b2f7Stbbdev 454*51c0b2f7Stbbdev #else // MALLOC_WINDOWS_OVERLOAD_ENABLED 455*51c0b2f7Stbbdev 456*51c0b2f7Stbbdev ptr = _aligned_malloc(minLargeObjectSize, 16); 457*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, minLargeObjectSize); 458*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, 16)); 459*51c0b2f7Stbbdev 460*51c0b2f7Stbbdev // Testing of workaround for vs "is power of 2 pow N" bug that accepts zeros 461*51c0b2f7Stbbdev void* ptr1 = _aligned_malloc(minLargeObjectSize, 0); 462*51c0b2f7Stbbdev scalableMallocCheckSize(ptr, minLargeObjectSize); 463*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, sizeof(void*))); 464*51c0b2f7Stbbdev _aligned_free(ptr1); 465*51c0b2f7Stbbdev 466*51c0b2f7Stbbdev ptr1 = _aligned_realloc(ptr, minLargeObjectSize*10, 16); 467*51c0b2f7Stbbdev scalableMallocCheckSize(ptr1, minLargeObjectSize*10); 468*51c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, 16)); 469*51c0b2f7Stbbdev _aligned_free(ptr1); 470*51c0b2f7Stbbdev 471*51c0b2f7Stbbdev FuncReplacementInfoCheck(); 472*51c0b2f7Stbbdev 473*51c0b2f7Stbbdev #endif 474*51c0b2f7Stbbdev CheckFreeAligned(); 475*51c0b2f7Stbbdev 476*51c0b2f7Stbbdev CheckNewDeleteOverload(); 477*51c0b2f7Stbbdev 478*51c0b2f7Stbbdev #if _WIN32 479*51c0b2f7Stbbdev std::string stdstring = "dependency on msvcpXX.dll"; 480*51c0b2f7Stbbdev REQUIRE(strcmp(stdstring.c_str(), "dependency on msvcpXX.dll") == 0); 481*51c0b2f7Stbbdev #endif 482*51c0b2f7Stbbdev TestZoneOverload(); 483*51c0b2f7Stbbdev TestRuntimeRoutines(); 484*51c0b2f7Stbbdev } 485*51c0b2f7Stbbdev #endif // !HARNESS_SKIP_TEST 486