151c0b2f7Stbbdev /*
2*9434ec94SIlya Isaev Copyright (c) 2005-2023 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:
BackRefIdx()1421ecde27fSIlya Mishin BackRefIdx() : main((uint16_t)-1) {}
isInvalid()1431ecde27fSIlya Mishin bool isInvalid() { return main == (uint16_t)-1; }
isLargeObject() const14451c0b2f7Stbbdev bool isLargeObject() const { return largeObj; }
getMain() const1451ecde27fSIlya Mishin uint16_t getMain() const { return main; }
getOffset() const14651c0b2f7Stbbdev 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
scalableMallocCheckSize(void * object,size_t size)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
CheckStdFuncOverload(void * (* malloc_p)(size_t),void * (* calloc_p)(size_t,size_t),void * (* realloc_p)(void *,size_t),void (* free_p)(void *))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
CheckMemalignFuncOverload(void * (* memalign_p)(size_t,size_t),void (* free_p)(void *))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
CheckVallocFuncOverload(void * (* valloc_p)(size_t),void (* free_p)(void *))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
CheckPvalloc(void * (* pvalloc_p)(size_t),void (* free_p)(void *))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
CheckFreeAligned()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++) {
27257f524caSIlya 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.
strdup(const char * str)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
TestZoneOverload()30151c0b2f7Stbbdev void TestZoneOverload() {
30251c0b2f7Stbbdev vm_address_t *zones;
30351c0b2f7Stbbdev unsigned zones_num;
30451c0b2f7Stbbdev
30557f524caSIlya 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.
TestRuntimeRoutines()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
CheckNewDeleteOverload()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
FuncReplacementInfoCheck()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
38657f524caSIlya 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
40357f524caSIlya 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
452*9434ec94SIlya Isaev #if __INTEL_COMPILER
453*9434ec94SIlya Isaev #pragma warning(push)
454*9434ec94SIlya Isaev #pragma warning(disable: 1478)
455*9434ec94SIlya Isaev #elif __GNUC__
45681dd27c4SAlex #pragma GCC diagnostic push
45781dd27c4SAlex #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
458*9434ec94SIlya Isaev #endif
45951c0b2f7Stbbdev struct mallinfo info = mallinfo();
460*9434ec94SIlya Isaev #if __INTEL_COMPILER
461*9434ec94SIlya Isaev #pragma warning(pop)
462*9434ec94SIlya Isaev #elif __GNUC__
46381dd27c4SAlex #pragma GCC diagnostic pop
464*9434ec94SIlya Isaev #endif
46551c0b2f7Stbbdev // right now mallinfo initialized by zero
46651c0b2f7Stbbdev REQUIRE((!info.arena && !info.ordblks && !info.smblks && !info.hblks
46751c0b2f7Stbbdev && !info.hblkhd && !info.usmblks && !info.fsmblks
46851c0b2f7Stbbdev && !info.uordblks && !info.fordblks && !info.keepcost));
46951c0b2f7Stbbdev
47051c0b2f7Stbbdev #if !__ANDROID__
47151c0b2f7Stbbdev // These non-standard functions are exported by GLIBC, and might be used
47251c0b2f7Stbbdev // in conjunction with standard malloc/free. Test that we overload them as well.
47351c0b2f7Stbbdev // Bionic doesn't have them.
47451c0b2f7Stbbdev CheckStdFuncOverload(__libc_malloc, __libc_calloc, __libc_realloc, __libc_free);
47551c0b2f7Stbbdev CheckMemalignFuncOverload(__libc_memalign, __libc_free);
47651c0b2f7Stbbdev CheckVallocFuncOverload(__libc_valloc, __libc_free);
47751c0b2f7Stbbdev CheckPvalloc(__libc_pvalloc, __libc_free);
47851c0b2f7Stbbdev #endif
479734f0bc0SPablo Romero #endif // __unix__
48051c0b2f7Stbbdev
48151c0b2f7Stbbdev #else // MALLOC_WINDOWS_OVERLOAD_ENABLED
48251c0b2f7Stbbdev
48351c0b2f7Stbbdev ptr = _aligned_malloc(minLargeObjectSize, 16);
48451c0b2f7Stbbdev scalableMallocCheckSize(ptr, minLargeObjectSize);
48551c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, 16));
48651c0b2f7Stbbdev
48751c0b2f7Stbbdev // Testing of workaround for vs "is power of 2 pow N" bug that accepts zeros
48851c0b2f7Stbbdev void* ptr1 = _aligned_malloc(minLargeObjectSize, 0);
48951c0b2f7Stbbdev scalableMallocCheckSize(ptr, minLargeObjectSize);
49051c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, sizeof(void*)));
49151c0b2f7Stbbdev _aligned_free(ptr1);
49251c0b2f7Stbbdev
49351c0b2f7Stbbdev ptr1 = _aligned_realloc(ptr, minLargeObjectSize*10, 16);
49451c0b2f7Stbbdev scalableMallocCheckSize(ptr1, minLargeObjectSize*10);
49551c0b2f7Stbbdev REQUIRE(tbb::detail::is_aligned(ptr, 16));
49651c0b2f7Stbbdev _aligned_free(ptr1);
49751c0b2f7Stbbdev
49851c0b2f7Stbbdev FuncReplacementInfoCheck();
49951c0b2f7Stbbdev
50051c0b2f7Stbbdev #endif
50151c0b2f7Stbbdev CheckFreeAligned();
50251c0b2f7Stbbdev
50351c0b2f7Stbbdev CheckNewDeleteOverload();
50451c0b2f7Stbbdev
50551c0b2f7Stbbdev #if _WIN32
50651c0b2f7Stbbdev std::string stdstring = "dependency on msvcpXX.dll";
50751c0b2f7Stbbdev REQUIRE(strcmp(stdstring.c_str(), "dependency on msvcpXX.dll") == 0);
50851c0b2f7Stbbdev #endif
50951c0b2f7Stbbdev TestZoneOverload();
51051c0b2f7Stbbdev TestRuntimeRoutines();
51151c0b2f7Stbbdev }
5124df48f98SAlex
5134df48f98SAlex //! Test address range tracker in backend that could be
5144df48f98SAlex //! broken during remap because of incorrect order of
5154df48f98SAlex //! deallocation event and the mremap system call
5164df48f98SAlex //! \brief \ref regression
5174df48f98SAlex TEST_CASE("Address range tracker regression test") {
5184df48f98SAlex int numThreads = 16;
__anon9013b3550102(int) 5194df48f98SAlex utils::NativeParallelFor(numThreads, [](int) {
5204df48f98SAlex void *ptr = nullptr;
5214df48f98SAlex for (int i = 0; i < 1000; ++i) {
5224df48f98SAlex for (int j = 0; j < 100; ++j) {
5234df48f98SAlex ptr = realloc(ptr, 1024*1024 + 4096*j);
5244df48f98SAlex }
5254df48f98SAlex }
5264df48f98SAlex free(ptr);
5274df48f98SAlex });
5284df48f98SAlex }
52951c0b2f7Stbbdev #endif // !HARNESS_SKIP_TEST
530