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