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_compliance.cpp 1851c0b2f7Stbbdev //! \brief Test for [memory_allocation.scalable_alloc_c_interface] functionality 1951c0b2f7Stbbdev 2051c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1 2151c0b2f7Stbbdev 2251c0b2f7Stbbdev #define __STDC_LIMIT_MACROS 1 // to get SIZE_MAX from stdint.h 2351c0b2f7Stbbdev 2451c0b2f7Stbbdev #include "common/test.h" 2551c0b2f7Stbbdev 2651c0b2f7Stbbdev #include "common/utils.h" 2751c0b2f7Stbbdev #include "common/utils_report.h" 2851c0b2f7Stbbdev #include "common/spin_barrier.h" 2951c0b2f7Stbbdev #include "common/memory_usage.h" 3051c0b2f7Stbbdev 3149e08aacStbbdev #include "oneapi/tbb/detail/_config.h" 3251c0b2f7Stbbdev 3351c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1 3451c0b2f7Stbbdev #include "tbb/scalable_allocator.h" 3551c0b2f7Stbbdev 3651c0b2f7Stbbdev #include <vector> 3751c0b2f7Stbbdev 3851c0b2f7Stbbdev #if _WIN32 || _WIN64 3951c0b2f7Stbbdev /** 4051c0b2f7Stbbdev * _WIN32_WINNT should be defined at the very beginning, 4151c0b2f7Stbbdev * because other headers might include <windows.h> 4251c0b2f7Stbbdev **/ 4351c0b2f7Stbbdev #undef _WIN32_WINNT 4451c0b2f7Stbbdev #define _WIN32_WINNT 0x0501 4551c0b2f7Stbbdev #include <windows.h> 4651c0b2f7Stbbdev #include <stdio.h> 4751c0b2f7Stbbdev 4851c0b2f7Stbbdev #if _MSC_VER && defined(_MT) && defined(_DLL) 4951c0b2f7Stbbdev #pragma comment(lib, "version.lib") // to use GetFileVersionInfo* 5051c0b2f7Stbbdev #endif 5151c0b2f7Stbbdev 5251c0b2f7Stbbdev void limitMem( size_t limit ) 5351c0b2f7Stbbdev { 5451c0b2f7Stbbdev static HANDLE hJob = NULL; 5551c0b2f7Stbbdev JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo; 5651c0b2f7Stbbdev 5751c0b2f7Stbbdev jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; 5851c0b2f7Stbbdev jobInfo.ProcessMemoryLimit = limit? limit*MByte : 2*MByte*1024; 5951c0b2f7Stbbdev if (NULL == hJob) { 6051c0b2f7Stbbdev if (NULL == (hJob = CreateJobObject(NULL, NULL))) { 6151c0b2f7Stbbdev REPORT("Can't assign create job object: %ld\n", GetLastError()); 6251c0b2f7Stbbdev exit(1); 6351c0b2f7Stbbdev } 6451c0b2f7Stbbdev if (0 == AssignProcessToJobObject(hJob, GetCurrentProcess())) { 6551c0b2f7Stbbdev REPORT("Can't assign process to job object: %ld\n", GetLastError()); 6651c0b2f7Stbbdev exit(1); 6751c0b2f7Stbbdev } 6851c0b2f7Stbbdev } 6951c0b2f7Stbbdev if (0 == SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, 7051c0b2f7Stbbdev &jobInfo, sizeof(jobInfo))) { 7151c0b2f7Stbbdev REPORT("Can't set limits: %ld\n", GetLastError()); 7251c0b2f7Stbbdev exit(1); 7351c0b2f7Stbbdev } 7451c0b2f7Stbbdev } 7551c0b2f7Stbbdev // Do not test errno with static VC runtime 7651c0b2f7Stbbdev #else // _WIN32 || _WIN64 7751c0b2f7Stbbdev #include <sys/resource.h> 7851c0b2f7Stbbdev #include <stdlib.h> 7951c0b2f7Stbbdev #include <stdio.h> 8051c0b2f7Stbbdev #include <errno.h> 8151c0b2f7Stbbdev #include <sys/types.h> // uint64_t on FreeBSD, needed for rlim_t 8251c0b2f7Stbbdev #include <stdint.h> // SIZE_MAX 8351c0b2f7Stbbdev 8451c0b2f7Stbbdev void limitMem( size_t limit ) 8551c0b2f7Stbbdev { 8651c0b2f7Stbbdev rlimit rlim; 8751c0b2f7Stbbdev int ret = getrlimit(RLIMIT_AS,&rlim); 8851c0b2f7Stbbdev if (0 != ret) { 8951c0b2f7Stbbdev REPORT("getrlimit() returned an error: errno %d\n", errno); 9051c0b2f7Stbbdev exit(1); 9151c0b2f7Stbbdev } 9251c0b2f7Stbbdev if (rlim.rlim_max==(rlim_t)RLIM_INFINITY) 9351c0b2f7Stbbdev rlim.rlim_cur = (limit > 0) ? limit*MByte : rlim.rlim_max; 94a3151ce8SIvan Kochin else rlim.rlim_cur = (limit > 0 && static_cast<rlim_t>(limit)<rlim.rlim_max) ? limit*MByte : rlim.rlim_max; 9551c0b2f7Stbbdev ret = setrlimit(RLIMIT_AS,&rlim); 9651c0b2f7Stbbdev if (0 != ret) { 9751c0b2f7Stbbdev REPORT("Can't set limits: errno %d\n", errno); 9851c0b2f7Stbbdev exit(1); 9951c0b2f7Stbbdev } 10051c0b2f7Stbbdev } 10151c0b2f7Stbbdev #endif // _WIN32 || _WIN64 10251c0b2f7Stbbdev 10351c0b2f7Stbbdev bool __tbb_test_errno = false; 10451c0b2f7Stbbdev 10551c0b2f7Stbbdev #define ASSERT_ERRNO(cond, msg) REQUIRE_MESSAGE( (!__tbb_test_errno || (cond)), msg ) 10651c0b2f7Stbbdev #define CHECK_ERRNO(cond) (__tbb_test_errno && (cond)) 10751c0b2f7Stbbdev 10851c0b2f7Stbbdev static const int MinThread = 1; 10951c0b2f7Stbbdev static const int MaxThread = 4; 11051c0b2f7Stbbdev static bool Verbose = false; 11151c0b2f7Stbbdev 11251c0b2f7Stbbdev #include <time.h> 11351c0b2f7Stbbdev #include <errno.h> 11451c0b2f7Stbbdev #include <limits.h> // for CHAR_BIT 11551c0b2f7Stbbdev 116734f0bc0SPablo Romero #if __unix__ 11751c0b2f7Stbbdev #include <stdint.h> // uintptr_t 11851c0b2f7Stbbdev #endif 11951c0b2f7Stbbdev #if _WIN32 || _WIN64 12051c0b2f7Stbbdev #include <malloc.h> // _aligned_(malloc|free|realloc) 12151c0b2f7Stbbdev #if __MINGW64__ 12251c0b2f7Stbbdev // Workaround a bug in MinGW64 headers with _aligned_(malloc|free) not declared by default 12351c0b2f7Stbbdev extern "C" void __cdecl _aligned_free(void *); 12451c0b2f7Stbbdev extern "C" void *__cdecl _aligned_malloc(size_t,size_t); 12551c0b2f7Stbbdev #endif 12651c0b2f7Stbbdev #endif 12751c0b2f7Stbbdev 12851c0b2f7Stbbdev #include <vector> 12951c0b2f7Stbbdev 13051c0b2f7Stbbdev const int COUNT_ELEM = 25000; 13151c0b2f7Stbbdev const size_t MAX_SIZE = 1000; 13251c0b2f7Stbbdev const int COUNTEXPERIMENT = 10000; 13351c0b2f7Stbbdev 13451c0b2f7Stbbdev const char strError[]="failed"; 13551c0b2f7Stbbdev const char strOk[]="done"; 13651c0b2f7Stbbdev 13751c0b2f7Stbbdev typedef unsigned int UINT; 13851c0b2f7Stbbdev typedef unsigned char UCHAR; 13951c0b2f7Stbbdev typedef unsigned long DWORD; 14051c0b2f7Stbbdev typedef unsigned char BYTE; 14151c0b2f7Stbbdev 14251c0b2f7Stbbdev typedef void* TestMalloc(size_t size); 14351c0b2f7Stbbdev typedef void* TestCalloc(size_t num, size_t size); 14451c0b2f7Stbbdev typedef void* TestRealloc(void* memblock, size_t size); 14551c0b2f7Stbbdev typedef void TestFree(void* memblock); 14651c0b2f7Stbbdev typedef int TestPosixMemalign(void **memptr, size_t alignment, size_t size); 14751c0b2f7Stbbdev typedef void* TestAlignedMalloc(size_t size, size_t alignment); 14851c0b2f7Stbbdev typedef void* TestAlignedRealloc(void* memblock, size_t size, size_t alignment); 14951c0b2f7Stbbdev typedef void TestAlignedFree(void* memblock); 15051c0b2f7Stbbdev 15151c0b2f7Stbbdev // pointers to tested functions 15251c0b2f7Stbbdev TestMalloc* Rmalloc; 15351c0b2f7Stbbdev TestCalloc* Rcalloc; 15451c0b2f7Stbbdev TestRealloc* Rrealloc; 15551c0b2f7Stbbdev TestFree* Tfree; 15651c0b2f7Stbbdev TestPosixMemalign* Rposix_memalign; 15751c0b2f7Stbbdev TestAlignedMalloc* Raligned_malloc; 15851c0b2f7Stbbdev TestAlignedRealloc* Raligned_realloc; 15951c0b2f7Stbbdev TestAlignedFree* Taligned_free; 16051c0b2f7Stbbdev 16151c0b2f7Stbbdev // call functions via pointer and check result's alignment 16251c0b2f7Stbbdev void* Tmalloc(size_t size); 16351c0b2f7Stbbdev void* Tcalloc(size_t num, size_t size); 16451c0b2f7Stbbdev void* Trealloc(void* memblock, size_t size); 16551c0b2f7Stbbdev int Tposix_memalign(void **memptr, size_t alignment, size_t size); 16651c0b2f7Stbbdev void* Taligned_malloc(size_t size, size_t alignment); 16751c0b2f7Stbbdev void* Taligned_realloc(void* memblock, size_t size, size_t alignment); 16851c0b2f7Stbbdev 169*a080baf9SAlex std::atomic<bool> error_occurred{ false }; 17051c0b2f7Stbbdev 17151c0b2f7Stbbdev #if __APPLE__ 17251c0b2f7Stbbdev // Tests that use the variables are skipped on macOS* 17351c0b2f7Stbbdev #else 17451c0b2f7Stbbdev const size_t COUNT_ELEM_CALLOC = 2; 17551c0b2f7Stbbdev const int COUNT_TESTS = 1000; 17651c0b2f7Stbbdev static bool perProcessLimits = true; 17751c0b2f7Stbbdev #endif 17851c0b2f7Stbbdev 17951c0b2f7Stbbdev const size_t POWERS_OF_2 = 20; 18051c0b2f7Stbbdev 18151c0b2f7Stbbdev struct MemStruct 18251c0b2f7Stbbdev { 18351c0b2f7Stbbdev void* Pointer; 18451c0b2f7Stbbdev UINT Size; 18551c0b2f7Stbbdev 18651c0b2f7Stbbdev MemStruct() : Pointer(NULL), Size(0) {} 18751c0b2f7Stbbdev MemStruct(void* ptr, UINT sz) : Pointer(ptr), Size(sz) {} 18851c0b2f7Stbbdev }; 18951c0b2f7Stbbdev 19051c0b2f7Stbbdev class CMemTest: utils::NoAssign 19151c0b2f7Stbbdev { 19251c0b2f7Stbbdev bool FullLog; 19351c0b2f7Stbbdev utils::SpinBarrier *limitBarrier; 19451c0b2f7Stbbdev static bool firstTime; 19551c0b2f7Stbbdev 19651c0b2f7Stbbdev public: 197*a080baf9SAlex CMemTest(utils::SpinBarrier *barrier, bool isVerbose=false) : limitBarrier(barrier) 19851c0b2f7Stbbdev { 19951c0b2f7Stbbdev srand((UINT)time(NULL)); 20051c0b2f7Stbbdev FullLog=isVerbose; 20151c0b2f7Stbbdev } 20251c0b2f7Stbbdev void NULLReturn(UINT MinSize, UINT MaxSize, int total_threads); // NULL pointer + check errno 20351c0b2f7Stbbdev void UniquePointer(); // unique pointer - check with padding 20451c0b2f7Stbbdev void AddrArifm(); // unique pointer - check with pointer arithmetic 20551c0b2f7Stbbdev bool ShouldReportError(); 20651c0b2f7Stbbdev void Free_NULL(); // 20751c0b2f7Stbbdev void Zerofilling(); // check if arrays are zero-filled 20851c0b2f7Stbbdev void TestAlignedParameters(); 20951c0b2f7Stbbdev void RunAllTests(int total_threads); 21051c0b2f7Stbbdev ~CMemTest() {} 21151c0b2f7Stbbdev }; 21251c0b2f7Stbbdev 21351c0b2f7Stbbdev class Limit { 21451c0b2f7Stbbdev size_t limit; 21551c0b2f7Stbbdev public: 21651c0b2f7Stbbdev Limit(size_t a_limit) : limit(a_limit) {} 21751c0b2f7Stbbdev void operator() () const { 21851c0b2f7Stbbdev limitMem(limit); 21951c0b2f7Stbbdev } 22051c0b2f7Stbbdev }; 22151c0b2f7Stbbdev 22251c0b2f7Stbbdev int argC; 22351c0b2f7Stbbdev char** argV; 22451c0b2f7Stbbdev 22551c0b2f7Stbbdev struct RoundRobin: utils::NoAssign { 22651c0b2f7Stbbdev const long number_of_threads; 22751c0b2f7Stbbdev mutable CMemTest test; 22851c0b2f7Stbbdev 22951c0b2f7Stbbdev RoundRobin( long p, utils::SpinBarrier *limitBarrier, bool verbose ) : 23051c0b2f7Stbbdev number_of_threads(p), test(limitBarrier, verbose) {} 23151c0b2f7Stbbdev void operator()( int /*id*/ ) const 23251c0b2f7Stbbdev { 23351c0b2f7Stbbdev test.RunAllTests(number_of_threads); 23451c0b2f7Stbbdev } 23551c0b2f7Stbbdev }; 23651c0b2f7Stbbdev 23751c0b2f7Stbbdev bool CMemTest::firstTime = true; 23851c0b2f7Stbbdev 23951c0b2f7Stbbdev inline size_t choose_random_alignment() { 24051c0b2f7Stbbdev return sizeof(void*)<<(rand() % POWERS_OF_2); 24151c0b2f7Stbbdev } 24251c0b2f7Stbbdev 24351c0b2f7Stbbdev #if TBB_REVAMP_TODO 24451c0b2f7Stbbdev // TODO: enable this test mode 24551c0b2f7Stbbdev static void setSystemAllocs() 24651c0b2f7Stbbdev { 24751c0b2f7Stbbdev Rmalloc=malloc; 24851c0b2f7Stbbdev Rrealloc=realloc; 24951c0b2f7Stbbdev Rcalloc=calloc; 25051c0b2f7Stbbdev Tfree=free; 25151c0b2f7Stbbdev #if _WIN32 || _WIN64 25251c0b2f7Stbbdev Raligned_malloc=_aligned_malloc; 25351c0b2f7Stbbdev Raligned_realloc=_aligned_realloc; 25451c0b2f7Stbbdev Taligned_free=_aligned_free; 25551c0b2f7Stbbdev Rposix_memalign=0; 25651c0b2f7Stbbdev #elif __APPLE__ || __sun || __ANDROID__ 25751c0b2f7Stbbdev // macOS, Solaris*, and Android* don't have posix_memalign 25851c0b2f7Stbbdev Raligned_malloc=0; 25951c0b2f7Stbbdev Raligned_realloc=0; 26051c0b2f7Stbbdev Taligned_free=0; 26151c0b2f7Stbbdev Rposix_memalign=0; 26251c0b2f7Stbbdev #else 26351c0b2f7Stbbdev Raligned_malloc=0; 26451c0b2f7Stbbdev Raligned_realloc=0; 26551c0b2f7Stbbdev Taligned_free=0; 26651c0b2f7Stbbdev Rposix_memalign=posix_memalign; 26751c0b2f7Stbbdev #endif 26851c0b2f7Stbbdev } 26951c0b2f7Stbbdev #endif 27051c0b2f7Stbbdev 27151c0b2f7Stbbdev // check that realloc works as free and as malloc 27251c0b2f7Stbbdev void ReallocParam() 27351c0b2f7Stbbdev { 27451c0b2f7Stbbdev const int ITERS = 1000; 27551c0b2f7Stbbdev int i; 27651c0b2f7Stbbdev void *bufs[ITERS]; 27751c0b2f7Stbbdev 27851c0b2f7Stbbdev bufs[0] = Trealloc(NULL, 30*MByte); 27951c0b2f7Stbbdev REQUIRE_MESSAGE(bufs[0], "Can't get memory to start the test."); 28051c0b2f7Stbbdev 28151c0b2f7Stbbdev for (i=1; i<ITERS; i++) 28251c0b2f7Stbbdev { 28351c0b2f7Stbbdev bufs[i] = Trealloc(NULL, 30*MByte); 28451c0b2f7Stbbdev if (NULL == bufs[i]) 28551c0b2f7Stbbdev break; 28651c0b2f7Stbbdev } 28751c0b2f7Stbbdev REQUIRE_MESSAGE(i<ITERS, "Limits should be decreased for the test to work."); 28851c0b2f7Stbbdev 28951c0b2f7Stbbdev Trealloc(bufs[0], 0); 29051c0b2f7Stbbdev /* There is a race for the free space between different threads at 29151c0b2f7Stbbdev this point. So, have to run the test sequentially. 29251c0b2f7Stbbdev */ 29351c0b2f7Stbbdev bufs[0] = Trealloc(NULL, 30*MByte); 29451c0b2f7Stbbdev REQUIRE(bufs[0]); 29551c0b2f7Stbbdev 29651c0b2f7Stbbdev for (int j=0; j<i; j++) 29751c0b2f7Stbbdev Trealloc(bufs[j], 0); 29851c0b2f7Stbbdev } 29951c0b2f7Stbbdev 30051c0b2f7Stbbdev void CheckArgumentsOverflow() 30151c0b2f7Stbbdev { 30251c0b2f7Stbbdev void *p; 30351c0b2f7Stbbdev const size_t params[] = {SIZE_MAX, SIZE_MAX-16}; 30451c0b2f7Stbbdev 30551c0b2f7Stbbdev for (unsigned i=0; i<utils::array_length(params); i++) { 30651c0b2f7Stbbdev p = Tmalloc(params[i]); 30751c0b2f7Stbbdev REQUIRE(!p); 30851c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 30951c0b2f7Stbbdev p = Trealloc(NULL, params[i]); 31051c0b2f7Stbbdev REQUIRE(!p); 31151c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 31251c0b2f7Stbbdev p = Tcalloc(1, params[i]); 31351c0b2f7Stbbdev REQUIRE(!p); 31451c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 31551c0b2f7Stbbdev p = Tcalloc(params[i], 1); 31651c0b2f7Stbbdev REQUIRE(!p); 31751c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 31851c0b2f7Stbbdev } 31951c0b2f7Stbbdev const size_t max_alignment = size_t(1) << (sizeof(size_t)*CHAR_BIT - 1); 32051c0b2f7Stbbdev if (Rposix_memalign) { 32151c0b2f7Stbbdev int ret = Rposix_memalign(&p, max_alignment, ~max_alignment); 32251c0b2f7Stbbdev REQUIRE(ret == ENOMEM); 32351c0b2f7Stbbdev for (unsigned i=0; i<utils::array_length(params); i++) { 32451c0b2f7Stbbdev ret = Rposix_memalign(&p, max_alignment, params[i]); 32551c0b2f7Stbbdev REQUIRE(ret == ENOMEM); 32651c0b2f7Stbbdev ret = Rposix_memalign(&p, sizeof(void*), params[i]); 32751c0b2f7Stbbdev REQUIRE(ret == ENOMEM); 32851c0b2f7Stbbdev } 32951c0b2f7Stbbdev } 33051c0b2f7Stbbdev if (Raligned_malloc) { 33151c0b2f7Stbbdev p = Raligned_malloc(~max_alignment, max_alignment); 33251c0b2f7Stbbdev REQUIRE(!p); 33351c0b2f7Stbbdev for (unsigned i=0; i<utils::array_length(params); i++) { 33451c0b2f7Stbbdev p = Raligned_malloc(params[i], max_alignment); 33551c0b2f7Stbbdev REQUIRE(!p); 33651c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 33751c0b2f7Stbbdev p = Raligned_malloc(params[i], sizeof(void*)); 33851c0b2f7Stbbdev REQUIRE(!p); 33951c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 34051c0b2f7Stbbdev } 34151c0b2f7Stbbdev } 34251c0b2f7Stbbdev 34351c0b2f7Stbbdev p = Tcalloc(SIZE_MAX/2-16, SIZE_MAX/2-16); 34451c0b2f7Stbbdev REQUIRE(!p); 34551c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 34651c0b2f7Stbbdev p = Tcalloc(SIZE_MAX/2, SIZE_MAX/2); 34751c0b2f7Stbbdev REQUIRE(!p); 34851c0b2f7Stbbdev ASSERT_ERRNO(errno==ENOMEM, NULL); 34951c0b2f7Stbbdev } 35051c0b2f7Stbbdev 35151c0b2f7Stbbdev void InvariantDataRealloc(bool aligned, size_t maxAllocSize, bool checkData) 35251c0b2f7Stbbdev { 35351c0b2f7Stbbdev utils::FastRandom<> fastRandom(1); 35451c0b2f7Stbbdev size_t size = 0, start = 0; 35551c0b2f7Stbbdev char *ptr = NULL, 356b15aabb3Stbbdev // external thread to create copies and compare ralloc result against it 35751c0b2f7Stbbdev *master = (char*)Tmalloc(2*maxAllocSize); 35851c0b2f7Stbbdev 35951c0b2f7Stbbdev REQUIRE(master); 36051c0b2f7Stbbdev REQUIRE_MESSAGE(!(2*maxAllocSize%sizeof(unsigned short)), 36151c0b2f7Stbbdev "The loop below expects that 2*maxAllocSize contains sizeof(unsigned short)"); 36251c0b2f7Stbbdev for (size_t k = 0; k<2*maxAllocSize; k+=sizeof(unsigned short)) 36351c0b2f7Stbbdev *(unsigned short*)(master+k) = fastRandom.get(); 36451c0b2f7Stbbdev 36551c0b2f7Stbbdev for (int i=0; i<100; i++) { 36651c0b2f7Stbbdev // don't want sizeNew==0 here 36751c0b2f7Stbbdev const size_t sizeNew = fastRandom.get() % (maxAllocSize-1) + 1; 36851c0b2f7Stbbdev char *ptrNew = aligned? 36951c0b2f7Stbbdev (char*)Taligned_realloc(ptr, sizeNew, choose_random_alignment()) 37051c0b2f7Stbbdev : (char*)Trealloc(ptr, sizeNew); 37151c0b2f7Stbbdev REQUIRE(ptrNew); 37251c0b2f7Stbbdev // check that old data not changed 37351c0b2f7Stbbdev if (checkData) 37451c0b2f7Stbbdev REQUIRE_MESSAGE(!memcmp(ptrNew, master+start, utils::min(size, sizeNew)), "broken data"); 37551c0b2f7Stbbdev 376b15aabb3Stbbdev // prepare fresh data, copying them from random position in external 37751c0b2f7Stbbdev size = sizeNew; 37851c0b2f7Stbbdev ptr = ptrNew; 37951c0b2f7Stbbdev if (checkData) { 38051c0b2f7Stbbdev start = fastRandom.get() % maxAllocSize; 38151c0b2f7Stbbdev memcpy(ptr, master+start, size); 38251c0b2f7Stbbdev } 38351c0b2f7Stbbdev } 38451c0b2f7Stbbdev if (aligned) 38551c0b2f7Stbbdev Taligned_realloc(ptr, 0, choose_random_alignment()); 38651c0b2f7Stbbdev else 38751c0b2f7Stbbdev Trealloc(ptr, 0); 38851c0b2f7Stbbdev Tfree(master); 38951c0b2f7Stbbdev } 39051c0b2f7Stbbdev 39151c0b2f7Stbbdev void CheckReallocLeak() 39251c0b2f7Stbbdev { 39351c0b2f7Stbbdev int i; 39451c0b2f7Stbbdev const int ITER_TO_STABILITY = 10; 39551c0b2f7Stbbdev // do bootstrap 39651c0b2f7Stbbdev for (int k=0; k<3; k++) 39751c0b2f7Stbbdev InvariantDataRealloc(/*aligned=*/false, 128*MByte, /*checkData=*/false); 39851c0b2f7Stbbdev size_t prev = utils::GetMemoryUsage(utils::peakUsage); 39951c0b2f7Stbbdev // expect realloc to not increase peak memory consumption after ITER_TO_STABILITY-1 iterations 40051c0b2f7Stbbdev for (i=0; i<ITER_TO_STABILITY; i++) { 40151c0b2f7Stbbdev for (int k=0; k<3; k++) 40251c0b2f7Stbbdev InvariantDataRealloc(/*aligned=*/false, 128*MByte, /*checkData=*/false); 40351c0b2f7Stbbdev size_t curr = utils::GetMemoryUsage(utils::peakUsage); 40451c0b2f7Stbbdev if (prev == curr) 40551c0b2f7Stbbdev break; 40651c0b2f7Stbbdev prev = curr; 40751c0b2f7Stbbdev } 40851c0b2f7Stbbdev REQUIRE_MESSAGE(i < ITER_TO_STABILITY, "Can't stabilize memory consumption."); 40951c0b2f7Stbbdev } 41051c0b2f7Stbbdev 41151c0b2f7Stbbdev // if non-zero byte found, returns bad value address plus 1 41251c0b2f7Stbbdev size_t NonZero(void *ptr, size_t size) 41351c0b2f7Stbbdev { 41451c0b2f7Stbbdev size_t words = size / sizeof(intptr_t); 41551c0b2f7Stbbdev size_t tailSz = size % sizeof(intptr_t); 41651c0b2f7Stbbdev intptr_t *buf =(intptr_t*)ptr; 41751c0b2f7Stbbdev char *bufTail =(char*)(buf+words); 41851c0b2f7Stbbdev 41951c0b2f7Stbbdev for (size_t i=0; i<words; i++) 42051c0b2f7Stbbdev if (buf[i]) { 42151c0b2f7Stbbdev for (unsigned b=0; b<sizeof(intptr_t); b++) 42251c0b2f7Stbbdev if (((char*)(buf+i))[b]) 42351c0b2f7Stbbdev return sizeof(intptr_t)*i + b + 1; 42451c0b2f7Stbbdev } 42551c0b2f7Stbbdev for (size_t i=0; i<tailSz; i++) 42651c0b2f7Stbbdev if (bufTail[i]) { 42751c0b2f7Stbbdev return words*sizeof(intptr_t)+i+1; 42851c0b2f7Stbbdev } 42951c0b2f7Stbbdev return 0; 43051c0b2f7Stbbdev } 43151c0b2f7Stbbdev 43251c0b2f7Stbbdev struct TestStruct 43351c0b2f7Stbbdev { 43451c0b2f7Stbbdev DWORD field1:2; 43551c0b2f7Stbbdev DWORD field2:6; 43651c0b2f7Stbbdev double field3; 43751c0b2f7Stbbdev UCHAR field4[100]; 43851c0b2f7Stbbdev TestStruct* field5; 43951c0b2f7Stbbdev std::vector<int> field7; 44051c0b2f7Stbbdev double field8; 44151c0b2f7Stbbdev }; 44251c0b2f7Stbbdev 44351c0b2f7Stbbdev void* Tmalloc(size_t size) 44451c0b2f7Stbbdev { 44551c0b2f7Stbbdev // For compatibility, on 64-bit systems malloc should align to 16 bytes 44651c0b2f7Stbbdev size_t alignment = (sizeof(intptr_t)>4 && size>8) ? 16 : 8; 44751c0b2f7Stbbdev void *ret = Rmalloc(size); 44851c0b2f7Stbbdev if (0 != ret) 449*a080baf9SAlex CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)), 45051c0b2f7Stbbdev "allocation result should be properly aligned"); 45151c0b2f7Stbbdev return ret; 45251c0b2f7Stbbdev } 45351c0b2f7Stbbdev void* Tcalloc(size_t num, size_t size) 45451c0b2f7Stbbdev { 45551c0b2f7Stbbdev // For compatibility, on 64-bit systems calloc should align to 16 bytes 45651c0b2f7Stbbdev size_t alignment = (sizeof(intptr_t)>4 && num && size>8) ? 16 : 8; 45751c0b2f7Stbbdev void *ret = Rcalloc(num, size); 45851c0b2f7Stbbdev if (0 != ret) 459*a080baf9SAlex CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)), 46051c0b2f7Stbbdev "allocation result should be properly aligned"); 46151c0b2f7Stbbdev return ret; 46251c0b2f7Stbbdev } 46351c0b2f7Stbbdev void* Trealloc(void* memblock, size_t size) 46451c0b2f7Stbbdev { 46551c0b2f7Stbbdev // For compatibility, on 64-bit systems realloc should align to 16 bytes 46651c0b2f7Stbbdev size_t alignment = (sizeof(intptr_t)>4 && size>8) ? 16 : 8; 46751c0b2f7Stbbdev void *ret = Rrealloc(memblock, size); 46851c0b2f7Stbbdev if (0 != ret) 469*a080baf9SAlex CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)), 47051c0b2f7Stbbdev "allocation result should be properly aligned"); 47151c0b2f7Stbbdev return ret; 47251c0b2f7Stbbdev } 47351c0b2f7Stbbdev int Tposix_memalign(void **memptr, size_t alignment, size_t size) 47451c0b2f7Stbbdev { 47551c0b2f7Stbbdev int ret = Rposix_memalign(memptr, alignment, size); 47651c0b2f7Stbbdev if (0 == ret) 477*a080baf9SAlex CHECK_FAST_MESSAGE(0==((uintptr_t)*memptr & (alignment-1)), 47851c0b2f7Stbbdev "allocation result should be aligned"); 47951c0b2f7Stbbdev return ret; 48051c0b2f7Stbbdev } 48151c0b2f7Stbbdev void* Taligned_malloc(size_t size, size_t alignment) 48251c0b2f7Stbbdev { 48351c0b2f7Stbbdev void *ret = Raligned_malloc(size, alignment); 48451c0b2f7Stbbdev if (0 != ret) 485*a080baf9SAlex CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)), 48651c0b2f7Stbbdev "allocation result should be aligned"); 48751c0b2f7Stbbdev return ret; 48851c0b2f7Stbbdev } 48951c0b2f7Stbbdev void* Taligned_realloc(void* memblock, size_t size, size_t alignment) 49051c0b2f7Stbbdev { 49151c0b2f7Stbbdev void *ret = Raligned_realloc(memblock, size, alignment); 49251c0b2f7Stbbdev if (0 != ret) 493*a080baf9SAlex CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)), 49451c0b2f7Stbbdev "allocation result should be aligned"); 49551c0b2f7Stbbdev return ret; 49651c0b2f7Stbbdev } 49751c0b2f7Stbbdev 49851c0b2f7Stbbdev struct PtrSize { 49951c0b2f7Stbbdev void *ptr; 50051c0b2f7Stbbdev size_t size; 50151c0b2f7Stbbdev }; 50251c0b2f7Stbbdev 50351c0b2f7Stbbdev static int cmpAddrs(const void *p1, const void *p2) 50451c0b2f7Stbbdev { 50551c0b2f7Stbbdev const PtrSize *a = (const PtrSize *)p1; 50651c0b2f7Stbbdev const PtrSize *b = (const PtrSize *)p2; 50751c0b2f7Stbbdev 50851c0b2f7Stbbdev return a->ptr < b->ptr ? -1 : ( a->ptr == b->ptr ? 0 : 1); 50951c0b2f7Stbbdev } 51051c0b2f7Stbbdev 51151c0b2f7Stbbdev void CMemTest::AddrArifm() 51251c0b2f7Stbbdev { 51351c0b2f7Stbbdev PtrSize *arr = (PtrSize*)Tmalloc(COUNT_ELEM*sizeof(PtrSize)); 51451c0b2f7Stbbdev 51551c0b2f7Stbbdev if (FullLog) REPORT("\nUnique pointer using Address arithmetic\n"); 51651c0b2f7Stbbdev if (FullLog) REPORT("malloc...."); 51751c0b2f7Stbbdev REQUIRE(arr); 51851c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 51951c0b2f7Stbbdev { 52051c0b2f7Stbbdev arr[i].size=rand()%MAX_SIZE; 52151c0b2f7Stbbdev arr[i].ptr=Tmalloc(arr[i].size); 52251c0b2f7Stbbdev } 52351c0b2f7Stbbdev qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs); 52451c0b2f7Stbbdev 52551c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM-1; i++) 52651c0b2f7Stbbdev { 52751c0b2f7Stbbdev if (NULL!=arr[i].ptr && NULL!=arr[i+1].ptr) 52851c0b2f7Stbbdev REQUIRE_MESSAGE((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr, 52951c0b2f7Stbbdev "intersection detected"); 53051c0b2f7Stbbdev } 53151c0b2f7Stbbdev //---------------------------------------------------------------- 53251c0b2f7Stbbdev if (FullLog) REPORT("realloc...."); 53351c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 53451c0b2f7Stbbdev { 53551c0b2f7Stbbdev size_t count=arr[i].size*2; 53651c0b2f7Stbbdev void *tmpAddr=Trealloc(arr[i].ptr,count); 53751c0b2f7Stbbdev if (NULL!=tmpAddr) { 53851c0b2f7Stbbdev arr[i].ptr = tmpAddr; 53951c0b2f7Stbbdev arr[i].size = count; 54051c0b2f7Stbbdev } else if (count==0) { // because realloc(..., 0) works as free 54151c0b2f7Stbbdev arr[i].ptr = NULL; 54251c0b2f7Stbbdev arr[i].size = 0; 54351c0b2f7Stbbdev } 54451c0b2f7Stbbdev } 54551c0b2f7Stbbdev qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs); 54651c0b2f7Stbbdev 54751c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM-1; i++) 54851c0b2f7Stbbdev { 54951c0b2f7Stbbdev if (NULL!=arr[i].ptr && NULL!=arr[i+1].ptr) 55051c0b2f7Stbbdev REQUIRE_MESSAGE((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr, 55151c0b2f7Stbbdev "intersection detected"); 55251c0b2f7Stbbdev } 55351c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 55451c0b2f7Stbbdev { 55551c0b2f7Stbbdev Tfree(arr[i].ptr); 55651c0b2f7Stbbdev } 55751c0b2f7Stbbdev //------------------------------------------- 55851c0b2f7Stbbdev if (FullLog) REPORT("calloc...."); 55951c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 56051c0b2f7Stbbdev { 56151c0b2f7Stbbdev arr[i].size=rand()%MAX_SIZE; 56251c0b2f7Stbbdev arr[i].ptr=Tcalloc(arr[i].size,1); 56351c0b2f7Stbbdev } 56451c0b2f7Stbbdev qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs); 56551c0b2f7Stbbdev 56651c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM-1; i++) 56751c0b2f7Stbbdev { 56851c0b2f7Stbbdev if (NULL!=arr[i].ptr && NULL!=arr[i+1].ptr) 56951c0b2f7Stbbdev REQUIRE_MESSAGE((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr, 57051c0b2f7Stbbdev "intersection detected"); 57151c0b2f7Stbbdev } 57251c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 57351c0b2f7Stbbdev { 57451c0b2f7Stbbdev Tfree(arr[i].ptr); 57551c0b2f7Stbbdev } 57651c0b2f7Stbbdev Tfree(arr); 57751c0b2f7Stbbdev } 57851c0b2f7Stbbdev 57951c0b2f7Stbbdev void CMemTest::Zerofilling() 58051c0b2f7Stbbdev { 58151c0b2f7Stbbdev TestStruct* TSMas; 58251c0b2f7Stbbdev size_t CountElement; 583*a080baf9SAlex static std::atomic<int> CountErrors{0}; 58451c0b2f7Stbbdev if (FullLog) REPORT("\nzeroings elements of array...."); 58551c0b2f7Stbbdev //test struct 58651c0b2f7Stbbdev for (int i=0; i<COUNTEXPERIMENT; i++) 58751c0b2f7Stbbdev { 58851c0b2f7Stbbdev CountElement=rand()%MAX_SIZE; 58951c0b2f7Stbbdev TSMas=(TestStruct*)Tcalloc(CountElement,sizeof(TestStruct)); 59051c0b2f7Stbbdev if (NULL == TSMas) 59151c0b2f7Stbbdev continue; 59251c0b2f7Stbbdev for (size_t j=0; j<CountElement; j++) 59351c0b2f7Stbbdev { 59451c0b2f7Stbbdev if (NonZero(TSMas+j, sizeof(TestStruct))) 59551c0b2f7Stbbdev { 59651c0b2f7Stbbdev CountErrors++; 59751c0b2f7Stbbdev if (ShouldReportError()) REPORT("detect nonzero element at TestStruct\n"); 59851c0b2f7Stbbdev } 59951c0b2f7Stbbdev } 60051c0b2f7Stbbdev Tfree(TSMas); 60151c0b2f7Stbbdev } 60251c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 60351c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 604*a080baf9SAlex if (CountErrors) error_occurred = true; 60551c0b2f7Stbbdev } 60651c0b2f7Stbbdev 60751c0b2f7Stbbdev #if !__APPLE__ 60851c0b2f7Stbbdev 60951c0b2f7Stbbdev void myMemset(void *ptr, int c, size_t n) 61051c0b2f7Stbbdev { 611734f0bc0SPablo Romero #if __unix__ && __i386__ 61251c0b2f7Stbbdev // memset in Fedora 13 not always correctly sets memory to required values. 61351c0b2f7Stbbdev char *p = (char*)ptr; 61451c0b2f7Stbbdev for (size_t i=0; i<n; i++) 61551c0b2f7Stbbdev p[i] = c; 61651c0b2f7Stbbdev #else 61751c0b2f7Stbbdev memset(ptr, c, n); 61851c0b2f7Stbbdev #endif 61951c0b2f7Stbbdev } 62051c0b2f7Stbbdev 62151c0b2f7Stbbdev // This test requires more than TOTAL_MB_ALLOC MB of RAM. 62251c0b2f7Stbbdev #if __ANDROID__ 62351c0b2f7Stbbdev // Android requires lower limit due to lack of virtual memory. 62451c0b2f7Stbbdev #define TOTAL_MB_ALLOC 200 62551c0b2f7Stbbdev #else 62651c0b2f7Stbbdev #define TOTAL_MB_ALLOC 800 62751c0b2f7Stbbdev #endif 62851c0b2f7Stbbdev void CMemTest::NULLReturn(UINT MinSize, UINT MaxSize, int total_threads) 62951c0b2f7Stbbdev { 63051c0b2f7Stbbdev const int MB_PER_THREAD = TOTAL_MB_ALLOC / total_threads; 63151c0b2f7Stbbdev // find size to guarantee getting NULL for 1024 B allocations 63251c0b2f7Stbbdev const int MAXNUM_1024 = (MB_PER_THREAD + (MB_PER_THREAD>>2)) * 1024; 63351c0b2f7Stbbdev 63451c0b2f7Stbbdev std::vector<MemStruct> PointerList; 63551c0b2f7Stbbdev void *tmp; 636*a080baf9SAlex static std::atomic<int> CountErrors{0}; 63751c0b2f7Stbbdev int CountNULL, num_1024; 63851c0b2f7Stbbdev if (FullLog) REPORT("\nNULL return & check errno:\n"); 63951c0b2f7Stbbdev UINT Size; 64051c0b2f7Stbbdev Limit limit_total(TOTAL_MB_ALLOC), no_limit(0); 64151c0b2f7Stbbdev void **buf_1024 = (void**)Tmalloc(MAXNUM_1024*sizeof(void*)); 64251c0b2f7Stbbdev 64351c0b2f7Stbbdev REQUIRE(buf_1024); 64451c0b2f7Stbbdev /* We must have space for pointers when memory limit is hit. 64551c0b2f7Stbbdev Reserve enough for the worst case, taking into account race for 64651c0b2f7Stbbdev limited space between threads. 64751c0b2f7Stbbdev */ 64851c0b2f7Stbbdev PointerList.reserve(TOTAL_MB_ALLOC*MByte/MinSize); 64951c0b2f7Stbbdev 65051c0b2f7Stbbdev /* There is a bug in the specific version of GLIBC (2.5-12) shipped 65151c0b2f7Stbbdev with RHEL5 that leads to erroneous working of the test 65251c0b2f7Stbbdev on Intel(R) 64 and Itanium(R) architecture when setrlimit-related part is enabled. 65351c0b2f7Stbbdev Switching to GLIBC 2.5-18 from RHEL5.1 resolved the issue. 65451c0b2f7Stbbdev */ 65551c0b2f7Stbbdev if (perProcessLimits) 65651c0b2f7Stbbdev limitBarrier->wait(limit_total); 65751c0b2f7Stbbdev else 65851c0b2f7Stbbdev limitMem(MB_PER_THREAD); 65951c0b2f7Stbbdev 66051c0b2f7Stbbdev /* regression test against the bug in allocator when it dereference NULL 66151c0b2f7Stbbdev while lack of memory 66251c0b2f7Stbbdev */ 66351c0b2f7Stbbdev for (num_1024=0; num_1024<MAXNUM_1024; num_1024++) { 66451c0b2f7Stbbdev buf_1024[num_1024] = Tcalloc(1024, 1); 66551c0b2f7Stbbdev if (! buf_1024[num_1024]) { 66651c0b2f7Stbbdev ASSERT_ERRNO(errno == ENOMEM, NULL); 66751c0b2f7Stbbdev break; 66851c0b2f7Stbbdev } 66951c0b2f7Stbbdev } 67051c0b2f7Stbbdev for (int i=0; i<num_1024; i++) 67151c0b2f7Stbbdev Tfree(buf_1024[i]); 67251c0b2f7Stbbdev Tfree(buf_1024); 67351c0b2f7Stbbdev 67451c0b2f7Stbbdev do { 67551c0b2f7Stbbdev Size=rand()%(MaxSize-MinSize)+MinSize; 67651c0b2f7Stbbdev tmp=Tmalloc(Size); 67751c0b2f7Stbbdev if (tmp != NULL) 67851c0b2f7Stbbdev { 67951c0b2f7Stbbdev myMemset(tmp, 0, Size); 68051c0b2f7Stbbdev PointerList.push_back(MemStruct(tmp, Size)); 68151c0b2f7Stbbdev } 68251c0b2f7Stbbdev } while(tmp != NULL); 68351c0b2f7Stbbdev ASSERT_ERRNO(errno == ENOMEM, NULL); 68451c0b2f7Stbbdev if (FullLog) REPORT("\n"); 68551c0b2f7Stbbdev 68651c0b2f7Stbbdev // preparation complete, now running tests 68751c0b2f7Stbbdev // malloc 68851c0b2f7Stbbdev if (FullLog) REPORT("malloc...."); 68951c0b2f7Stbbdev CountNULL = 0; 69051c0b2f7Stbbdev while (CountNULL==0) 69151c0b2f7Stbbdev for (int j=0; j<COUNT_TESTS; j++) 69251c0b2f7Stbbdev { 69351c0b2f7Stbbdev Size=rand()%(MaxSize-MinSize)+MinSize; 69451c0b2f7Stbbdev errno = ENOMEM+j+1; 69551c0b2f7Stbbdev tmp=Tmalloc(Size); 69651c0b2f7Stbbdev if (tmp == NULL) 69751c0b2f7Stbbdev { 69851c0b2f7Stbbdev CountNULL++; 69951c0b2f7Stbbdev if ( CHECK_ERRNO(errno != ENOMEM) ) { 70051c0b2f7Stbbdev CountErrors++; 70151c0b2f7Stbbdev if (ShouldReportError()) REPORT("NULL returned, error: errno (%d) != ENOMEM\n", errno); 70251c0b2f7Stbbdev } 70351c0b2f7Stbbdev } 70451c0b2f7Stbbdev else 70551c0b2f7Stbbdev { 70651c0b2f7Stbbdev // Technically, if malloc returns a non-NULL pointer, it is allowed to set errno anyway. 70751c0b2f7Stbbdev // However, on most systems it does not set errno. 70851c0b2f7Stbbdev bool known_issue = false; 709734f0bc0SPablo Romero #if __unix__ || __ANDROID__ 71051c0b2f7Stbbdev if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true; 711734f0bc0SPablo Romero #endif /* __unix__ */ 71251c0b2f7Stbbdev if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue) { 71351c0b2f7Stbbdev CountErrors++; 71451c0b2f7Stbbdev if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno); 71551c0b2f7Stbbdev } 71651c0b2f7Stbbdev myMemset(tmp, 0, Size); 71751c0b2f7Stbbdev PointerList.push_back(MemStruct(tmp, Size)); 71851c0b2f7Stbbdev } 71951c0b2f7Stbbdev } 72051c0b2f7Stbbdev if (FullLog) REPORT("end malloc\n"); 72151c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 72251c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 723*a080baf9SAlex if (CountErrors) error_occurred = true; 72451c0b2f7Stbbdev 72551c0b2f7Stbbdev //calloc 72651c0b2f7Stbbdev if (FullLog) REPORT("calloc...."); 72751c0b2f7Stbbdev CountNULL = 0; 72851c0b2f7Stbbdev while (CountNULL==0) 72951c0b2f7Stbbdev for (int j=0; j<COUNT_TESTS; j++) 73051c0b2f7Stbbdev { 73151c0b2f7Stbbdev Size=rand()%(MaxSize-MinSize)+MinSize; 73251c0b2f7Stbbdev errno = ENOMEM+j+1; 73351c0b2f7Stbbdev tmp=Tcalloc(COUNT_ELEM_CALLOC,Size); 73451c0b2f7Stbbdev if (tmp == NULL) 73551c0b2f7Stbbdev { 73651c0b2f7Stbbdev CountNULL++; 73751c0b2f7Stbbdev if ( CHECK_ERRNO(errno != ENOMEM) ){ 73851c0b2f7Stbbdev CountErrors++; 73951c0b2f7Stbbdev if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno); 74051c0b2f7Stbbdev } 74151c0b2f7Stbbdev } 74251c0b2f7Stbbdev else 74351c0b2f7Stbbdev { 74451c0b2f7Stbbdev // Technically, if calloc returns a non-NULL pointer, it is allowed to set errno anyway. 74551c0b2f7Stbbdev // However, on most systems it does not set errno. 74651c0b2f7Stbbdev bool known_issue = false; 747734f0bc0SPablo Romero #if __unix__ 74851c0b2f7Stbbdev if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true; 749734f0bc0SPablo Romero #endif /* __unix__ */ 75051c0b2f7Stbbdev if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue ) { 75151c0b2f7Stbbdev CountErrors++; 75251c0b2f7Stbbdev if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno); 75351c0b2f7Stbbdev } 75451c0b2f7Stbbdev PointerList.push_back(MemStruct(tmp, Size)); 75551c0b2f7Stbbdev } 75651c0b2f7Stbbdev } 75751c0b2f7Stbbdev if (FullLog) REPORT("end calloc\n"); 75851c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 75951c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 760*a080baf9SAlex if (CountErrors) error_occurred = true; 76151c0b2f7Stbbdev if (FullLog) REPORT("realloc...."); 76251c0b2f7Stbbdev CountNULL = 0; 76351c0b2f7Stbbdev if (PointerList.size() > 0) 76451c0b2f7Stbbdev while (CountNULL==0) 76551c0b2f7Stbbdev for (size_t i=0; i<(size_t)COUNT_TESTS && i<PointerList.size(); i++) 76651c0b2f7Stbbdev { 76751c0b2f7Stbbdev errno = 0; 76851c0b2f7Stbbdev tmp=Trealloc(PointerList[i].Pointer,PointerList[i].Size*2); 76951c0b2f7Stbbdev if (tmp != NULL) // same or another place 77051c0b2f7Stbbdev { 77151c0b2f7Stbbdev bool known_issue = false; 772734f0bc0SPablo Romero #if __unix__ 77351c0b2f7Stbbdev if( errno==ENOMEM ) known_issue = true; 774734f0bc0SPablo Romero #endif /* __unix__ */ 77551c0b2f7Stbbdev if (errno != 0 && !known_issue) { 77651c0b2f7Stbbdev CountErrors++; 77751c0b2f7Stbbdev if (ShouldReportError()) REPORT("valid pointer returned, error: errno not kept\n"); 77851c0b2f7Stbbdev } 77951c0b2f7Stbbdev // newly allocated area have to be zeroed 78051c0b2f7Stbbdev myMemset((char*)tmp + PointerList[i].Size, 0, PointerList[i].Size); 78151c0b2f7Stbbdev PointerList[i].Pointer = tmp; 78251c0b2f7Stbbdev PointerList[i].Size *= 2; 78351c0b2f7Stbbdev } else { 78451c0b2f7Stbbdev CountNULL++; 78551c0b2f7Stbbdev if ( CHECK_ERRNO(errno != ENOMEM) ) 78651c0b2f7Stbbdev { 78751c0b2f7Stbbdev CountErrors++; 78851c0b2f7Stbbdev if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno); 78951c0b2f7Stbbdev } 79051c0b2f7Stbbdev // check data integrity 79151c0b2f7Stbbdev if (NonZero(PointerList[i].Pointer, PointerList[i].Size)) { 79251c0b2f7Stbbdev CountErrors++; 79351c0b2f7Stbbdev if (ShouldReportError()) REPORT("NULL returned, error: data changed\n"); 79451c0b2f7Stbbdev } 79551c0b2f7Stbbdev } 79651c0b2f7Stbbdev } 79751c0b2f7Stbbdev if (FullLog) REPORT("realloc end\n"); 79851c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 79951c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 800*a080baf9SAlex if (CountErrors) error_occurred = true; 80151c0b2f7Stbbdev for (UINT i=0; i<PointerList.size(); i++) 80251c0b2f7Stbbdev { 80351c0b2f7Stbbdev Tfree(PointerList[i].Pointer); 80451c0b2f7Stbbdev } 80551c0b2f7Stbbdev 80651c0b2f7Stbbdev if (perProcessLimits) 80751c0b2f7Stbbdev limitBarrier->wait(no_limit); 80851c0b2f7Stbbdev else 80951c0b2f7Stbbdev limitMem(0); 81051c0b2f7Stbbdev } 81151c0b2f7Stbbdev #endif /* #if !__APPLE__ */ 81251c0b2f7Stbbdev 81351c0b2f7Stbbdev void CMemTest::UniquePointer() 81451c0b2f7Stbbdev { 815*a080baf9SAlex static std::atomic<int> CountErrors{0}; 81651c0b2f7Stbbdev int **MasPointer = (int **)Tmalloc(sizeof(int*)*COUNT_ELEM); 81751c0b2f7Stbbdev size_t *MasCountElem = (size_t*)Tmalloc(sizeof(size_t)*COUNT_ELEM); 81851c0b2f7Stbbdev if (FullLog) REPORT("\nUnique pointer using 0\n"); 81951c0b2f7Stbbdev REQUIRE((MasCountElem && MasPointer)); 82051c0b2f7Stbbdev // 82151c0b2f7Stbbdev //------------------------------------------------------- 82251c0b2f7Stbbdev //malloc 82351c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 82451c0b2f7Stbbdev { 82551c0b2f7Stbbdev MasCountElem[i]=rand()%MAX_SIZE; 82651c0b2f7Stbbdev MasPointer[i]=(int*)Tmalloc(MasCountElem[i]*sizeof(int)); 82751c0b2f7Stbbdev if (NULL == MasPointer[i]) 82851c0b2f7Stbbdev MasCountElem[i]=0; 82951c0b2f7Stbbdev memset(MasPointer[i], 0, sizeof(int)*MasCountElem[i]); 83051c0b2f7Stbbdev } 83151c0b2f7Stbbdev if (FullLog) REPORT("malloc...."); 83251c0b2f7Stbbdev for (UINT i=0; i<COUNT_ELEM-1; i++) 83351c0b2f7Stbbdev { 83451c0b2f7Stbbdev if (size_t badOff = NonZero(MasPointer[i], sizeof(int)*MasCountElem[i])) { 83551c0b2f7Stbbdev CountErrors++; 83651c0b2f7Stbbdev if (ShouldReportError()) 83751c0b2f7Stbbdev REPORT("error, detect non-zero at %p\n", (char*)MasPointer[i]+badOff-1); 83851c0b2f7Stbbdev } 83951c0b2f7Stbbdev memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]); 84051c0b2f7Stbbdev } 84151c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 84251c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 843*a080baf9SAlex if (CountErrors) error_occurred = true; 84451c0b2f7Stbbdev //---------------------------------------------------------- 84551c0b2f7Stbbdev //calloc 84651c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 84751c0b2f7Stbbdev Tfree(MasPointer[i]); 84851c0b2f7Stbbdev for (long i=0; i<COUNT_ELEM; i++) 84951c0b2f7Stbbdev { 85051c0b2f7Stbbdev MasPointer[i]=(int*)Tcalloc(MasCountElem[i]*sizeof(int),2); 85151c0b2f7Stbbdev if (NULL == MasPointer[i]) 85251c0b2f7Stbbdev MasCountElem[i]=0; 85351c0b2f7Stbbdev } 85451c0b2f7Stbbdev if (FullLog) REPORT("calloc...."); 85551c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM-1; i++) 85651c0b2f7Stbbdev { 85751c0b2f7Stbbdev if (size_t badOff = NonZero(MasPointer[i], sizeof(int)*MasCountElem[i])) { 85851c0b2f7Stbbdev CountErrors++; 85951c0b2f7Stbbdev if (ShouldReportError()) 86051c0b2f7Stbbdev REPORT("error, detect non-zero at %p\n", (char*)MasPointer[i]+badOff-1); 86151c0b2f7Stbbdev } 86251c0b2f7Stbbdev memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]); 86351c0b2f7Stbbdev } 86451c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 86551c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 866*a080baf9SAlex if (CountErrors) error_occurred = true; 86751c0b2f7Stbbdev //--------------------------------------------------------- 86851c0b2f7Stbbdev //realloc 86951c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 87051c0b2f7Stbbdev { 87151c0b2f7Stbbdev MasCountElem[i]*=2; 87251c0b2f7Stbbdev *(MasPointer+i)= 87351c0b2f7Stbbdev (int*)Trealloc(*(MasPointer+i),MasCountElem[i]*sizeof(int)); 87451c0b2f7Stbbdev if (NULL == MasPointer[i]) 87551c0b2f7Stbbdev MasCountElem[i]=0; 87651c0b2f7Stbbdev memset(MasPointer[i], 0, sizeof(int)*MasCountElem[i]); 87751c0b2f7Stbbdev } 87851c0b2f7Stbbdev if (FullLog) REPORT("realloc...."); 87951c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM-1; i++) 88051c0b2f7Stbbdev { 88151c0b2f7Stbbdev if (NonZero(MasPointer[i], sizeof(int)*MasCountElem[i])) 88251c0b2f7Stbbdev CountErrors++; 88351c0b2f7Stbbdev memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]); 88451c0b2f7Stbbdev } 88551c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 88651c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 887*a080baf9SAlex if (CountErrors) error_occurred = true; 88851c0b2f7Stbbdev for (int i=0; i<COUNT_ELEM; i++) 88951c0b2f7Stbbdev Tfree(MasPointer[i]); 89051c0b2f7Stbbdev Tfree(MasCountElem); 89151c0b2f7Stbbdev Tfree(MasPointer); 89251c0b2f7Stbbdev } 89351c0b2f7Stbbdev 89451c0b2f7Stbbdev bool CMemTest::ShouldReportError() 89551c0b2f7Stbbdev { 89651c0b2f7Stbbdev if (FullLog) 89751c0b2f7Stbbdev return true; 89851c0b2f7Stbbdev else 89951c0b2f7Stbbdev if (firstTime) { 90051c0b2f7Stbbdev firstTime = false; 90151c0b2f7Stbbdev return true; 90251c0b2f7Stbbdev } else 90351c0b2f7Stbbdev return false; 90451c0b2f7Stbbdev } 90551c0b2f7Stbbdev 90651c0b2f7Stbbdev void CMemTest::Free_NULL() 90751c0b2f7Stbbdev { 908*a080baf9SAlex static std::atomic<int> CountErrors{0}; 90951c0b2f7Stbbdev if (FullLog) REPORT("\ncall free with parameter NULL...."); 91051c0b2f7Stbbdev errno = 0; 91151c0b2f7Stbbdev for (int i=0; i<COUNTEXPERIMENT; i++) 91251c0b2f7Stbbdev { 91351c0b2f7Stbbdev Tfree(NULL); 91451c0b2f7Stbbdev if (CHECK_ERRNO(errno)) 91551c0b2f7Stbbdev { 91651c0b2f7Stbbdev CountErrors++; 91751c0b2f7Stbbdev if (ShouldReportError()) REPORT("error is found by a call free with parameter NULL\n"); 91851c0b2f7Stbbdev } 91951c0b2f7Stbbdev } 92051c0b2f7Stbbdev if (CountErrors) REPORT("%s\n",strError); 92151c0b2f7Stbbdev else if (FullLog) REPORT("%s\n",strOk); 922*a080baf9SAlex if (CountErrors) error_occurred = true; 92351c0b2f7Stbbdev } 92451c0b2f7Stbbdev 92551c0b2f7Stbbdev void CMemTest::TestAlignedParameters() 92651c0b2f7Stbbdev { 92751c0b2f7Stbbdev void *memptr; 92851c0b2f7Stbbdev int ret; 92951c0b2f7Stbbdev 93051c0b2f7Stbbdev if (Rposix_memalign) { 93151c0b2f7Stbbdev // alignment isn't power of 2 93251c0b2f7Stbbdev for (int bad_align=3; bad_align<16; bad_align++) 93351c0b2f7Stbbdev if (bad_align&(bad_align-1)) { 93451c0b2f7Stbbdev ret = Tposix_memalign(NULL, bad_align, 100); 93551c0b2f7Stbbdev REQUIRE(EINVAL==ret); 93651c0b2f7Stbbdev } 93751c0b2f7Stbbdev 93851c0b2f7Stbbdev memptr = &ret; 93951c0b2f7Stbbdev ret = Tposix_memalign(&memptr, 5*sizeof(void*), 100); 94051c0b2f7Stbbdev REQUIRE_MESSAGE(memptr == &ret, 94151c0b2f7Stbbdev "memptr should not be changed after unsuccessful call"); 94251c0b2f7Stbbdev REQUIRE(EINVAL==ret); 94351c0b2f7Stbbdev 94451c0b2f7Stbbdev // alignment is power of 2, but not a multiple of sizeof(void *), 94551c0b2f7Stbbdev // we expect that sizeof(void*) > 2 94651c0b2f7Stbbdev ret = Tposix_memalign(NULL, 2, 100); 94751c0b2f7Stbbdev REQUIRE(EINVAL==ret); 94851c0b2f7Stbbdev } 94951c0b2f7Stbbdev if (Raligned_malloc) { 95051c0b2f7Stbbdev // alignment isn't power of 2 95151c0b2f7Stbbdev for (int bad_align=3; bad_align<16; bad_align++) 95251c0b2f7Stbbdev if (bad_align&(bad_align-1)) { 95351c0b2f7Stbbdev memptr = Taligned_malloc(100, bad_align); 95451c0b2f7Stbbdev REQUIRE(memptr == nullptr); 95551c0b2f7Stbbdev ASSERT_ERRNO(EINVAL==errno, NULL); 95651c0b2f7Stbbdev } 95751c0b2f7Stbbdev 95851c0b2f7Stbbdev // size is zero 95951c0b2f7Stbbdev memptr = Taligned_malloc(0, 16); 96051c0b2f7Stbbdev REQUIRE_MESSAGE(memptr == nullptr, "size is zero, so must return NULL"); 96151c0b2f7Stbbdev ASSERT_ERRNO(EINVAL==errno, NULL); 96251c0b2f7Stbbdev } 96351c0b2f7Stbbdev if (Taligned_free) { 96451c0b2f7Stbbdev // NULL pointer is OK to free 96551c0b2f7Stbbdev errno = 0; 96651c0b2f7Stbbdev Taligned_free(NULL); 96751c0b2f7Stbbdev /* As there is no return value for free, strictly speaking we can't 96851c0b2f7Stbbdev check errno here. But checked implementations obey the assertion. 96951c0b2f7Stbbdev */ 97051c0b2f7Stbbdev ASSERT_ERRNO(0==errno, NULL); 97151c0b2f7Stbbdev } 97251c0b2f7Stbbdev if (Raligned_realloc) { 97351c0b2f7Stbbdev for (int i=1; i<20; i++) { 97451c0b2f7Stbbdev // checks that calls work correctly in presence of non-zero errno 97551c0b2f7Stbbdev errno = i; 97651c0b2f7Stbbdev void *ptr = Taligned_malloc(i*10, 128); 97751c0b2f7Stbbdev REQUIRE(ptr != nullptr); 97851c0b2f7Stbbdev ASSERT_ERRNO(0!=errno, NULL); 97951c0b2f7Stbbdev // if size is zero and pointer is not NULL, works like free 98051c0b2f7Stbbdev memptr = Taligned_realloc(ptr, 0, 64); 98151c0b2f7Stbbdev REQUIRE(memptr == nullptr); 98251c0b2f7Stbbdev ASSERT_ERRNO(0!=errno, NULL); 98351c0b2f7Stbbdev } 98451c0b2f7Stbbdev // alignment isn't power of 2 98551c0b2f7Stbbdev for (int bad_align=3; bad_align<16; bad_align++) 98651c0b2f7Stbbdev if (bad_align&(bad_align-1)) { 98751c0b2f7Stbbdev void *ptr = &bad_align; 98851c0b2f7Stbbdev memptr = Taligned_realloc(&ptr, 100, bad_align); 98951c0b2f7Stbbdev REQUIRE(memptr == nullptr); 99051c0b2f7Stbbdev REQUIRE(&bad_align==ptr); 99151c0b2f7Stbbdev ASSERT_ERRNO(EINVAL==errno, NULL); 99251c0b2f7Stbbdev } 99351c0b2f7Stbbdev } 99451c0b2f7Stbbdev } 99551c0b2f7Stbbdev 99651c0b2f7Stbbdev void CMemTest::RunAllTests(int total_threads) 99751c0b2f7Stbbdev { 99851c0b2f7Stbbdev Zerofilling(); 99951c0b2f7Stbbdev Free_NULL(); 100051c0b2f7Stbbdev InvariantDataRealloc(/*aligned=*/false, 8*MByte, /*checkData=*/true); 100151c0b2f7Stbbdev if (Raligned_realloc) 100251c0b2f7Stbbdev InvariantDataRealloc(/*aligned=*/true, 8*MByte, /*checkData=*/true); 100351c0b2f7Stbbdev TestAlignedParameters(); 100451c0b2f7Stbbdev UniquePointer(); 100551c0b2f7Stbbdev AddrArifm(); 1006*a080baf9SAlex #if __APPLE__ || __TBB_USE_THREAD_SANITIZER 100751c0b2f7Stbbdev REPORT("Known issue: some tests are skipped on macOS\n"); 100851c0b2f7Stbbdev #else 1009*a080baf9SAlex // TODO: enable 101051c0b2f7Stbbdev NULLReturn(1*MByte,100*MByte,total_threads); 101151c0b2f7Stbbdev #endif 101251c0b2f7Stbbdev if (FullLog) REPORT("Tests for %d threads ended\n", total_threads); 101351c0b2f7Stbbdev } 101451c0b2f7Stbbdev 101551c0b2f7Stbbdev // TODO: fix the tests to support UWP mode 101651c0b2f7Stbbdev #if !__TBB_WIN8UI_SUPPORT 101751c0b2f7Stbbdev 101851c0b2f7Stbbdev TEST_CASE("MAIN TEST") { 101951c0b2f7Stbbdev Rmalloc=scalable_malloc; 102051c0b2f7Stbbdev Rrealloc=scalable_realloc; 102151c0b2f7Stbbdev Rcalloc=scalable_calloc; 102251c0b2f7Stbbdev Tfree=scalable_free; 102351c0b2f7Stbbdev Rposix_memalign=scalable_posix_memalign; 102451c0b2f7Stbbdev Raligned_malloc=scalable_aligned_malloc; 102551c0b2f7Stbbdev Raligned_realloc=scalable_aligned_realloc; 102651c0b2f7Stbbdev Taligned_free=scalable_aligned_free; 102751c0b2f7Stbbdev 102851c0b2f7Stbbdev // Check if we were called to test standard behavior 102951c0b2f7Stbbdev // TODO: enable this mode 103051c0b2f7Stbbdev // setSystemAllocs(); 1031734f0bc0SPablo Romero #if __unix__ 103251c0b2f7Stbbdev /* According to man pthreads 103351c0b2f7Stbbdev "NPTL threads do not share resource limits (fixed in kernel 2.6.10)". 103451c0b2f7Stbbdev Use per-threads limits for affected systems. 103551c0b2f7Stbbdev */ 103651c0b2f7Stbbdev if ( utils::LinuxKernelVersion() < 2*1000000 + 6*1000 + 10) 103751c0b2f7Stbbdev perProcessLimits = false; 103851c0b2f7Stbbdev #endif 103951c0b2f7Stbbdev //------------------------------------- 1040*a080baf9SAlex #if __APPLE__ || __TBB_USE_SANITIZERS 104151c0b2f7Stbbdev /* Skip due to lack of memory limit enforcing under macOS. */ 1042c0b91bdbSAnton Potapov //Skip this test under ASAN , as OOM condition breaks the ASAN as well 104351c0b2f7Stbbdev #else 104451c0b2f7Stbbdev limitMem(200); 104551c0b2f7Stbbdev ReallocParam(); 104651c0b2f7Stbbdev limitMem(0); 104751c0b2f7Stbbdev #endif 104851c0b2f7Stbbdev 104951c0b2f7Stbbdev //for linux and dynamic runtime errno is used to check allocator functions 105051c0b2f7Stbbdev //check if library compiled with /MD(d) and we can use errno 105151c0b2f7Stbbdev #if _MSC_VER 105251c0b2f7Stbbdev #if defined(_MT) && defined(_DLL) //check errno if test itself compiled with /MD(d) only 105351c0b2f7Stbbdev char* version_info_block = NULL; 105451c0b2f7Stbbdev int version_info_block_size; 105551c0b2f7Stbbdev LPVOID comments_block = NULL; 105651c0b2f7Stbbdev UINT comments_block_size; 105751c0b2f7Stbbdev #ifdef _DEBUG 105851c0b2f7Stbbdev #define __TBBMALLOCDLL "tbbmalloc_debug.dll" 105951c0b2f7Stbbdev #else //_DEBUG 106051c0b2f7Stbbdev #define __TBBMALLOCDLL "tbbmalloc.dll" 106151c0b2f7Stbbdev #endif //_DEBUG 106251c0b2f7Stbbdev version_info_block_size = GetFileVersionInfoSize( __TBBMALLOCDLL, (LPDWORD)&version_info_block_size ); 106351c0b2f7Stbbdev if( version_info_block_size 106451c0b2f7Stbbdev && ((version_info_block = (char*)malloc(version_info_block_size)) != NULL) 106551c0b2f7Stbbdev && GetFileVersionInfo( __TBBMALLOCDLL, NULL, version_info_block_size, version_info_block ) 106651c0b2f7Stbbdev && VerQueryValue( version_info_block, "\\StringFileInfo\\000004b0\\Comments", &comments_block, &comments_block_size ) 106751c0b2f7Stbbdev && strstr( (char*)comments_block, "/MD" ) 106851c0b2f7Stbbdev ){ 106951c0b2f7Stbbdev __tbb_test_errno = true; 107051c0b2f7Stbbdev } 107151c0b2f7Stbbdev if( version_info_block ) free( version_info_block ); 107251c0b2f7Stbbdev #endif // defined(_MT) && defined(_DLL) 107351c0b2f7Stbbdev #else // _MSC_VER 107451c0b2f7Stbbdev __tbb_test_errno = true; 107551c0b2f7Stbbdev #endif // _MSC_VER 107651c0b2f7Stbbdev 107751c0b2f7Stbbdev CheckArgumentsOverflow(); 107851c0b2f7Stbbdev CheckReallocLeak(); 107951c0b2f7Stbbdev for( int p=MaxThread; p>=MinThread; --p ) { 108051c0b2f7Stbbdev for (int limit=0; limit<2; limit++) { 108151c0b2f7Stbbdev int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT, 16*1024*limit); 108251c0b2f7Stbbdev REQUIRE(ret==TBBMALLOC_OK); 108351c0b2f7Stbbdev utils::SpinBarrier *barrier = new utils::SpinBarrier(p); 108451c0b2f7Stbbdev utils::NativeParallelFor( p, RoundRobin(p, barrier, Verbose) ); 108551c0b2f7Stbbdev delete barrier; 108651c0b2f7Stbbdev } 108751c0b2f7Stbbdev } 108851c0b2f7Stbbdev int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT, 0); 108951c0b2f7Stbbdev REQUIRE(ret==TBBMALLOC_OK); 109051c0b2f7Stbbdev REQUIRE(!error_occurred); 109151c0b2f7Stbbdev } 109251c0b2f7Stbbdev 109351c0b2f7Stbbdev #endif /* __TBB_WIN8UI_SUPPORT */ 1094