151c0b2f7Stbbdev /*
2*ab7f370cSPavel Kumbrasev     Copyright (c) 2005-2023 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev //! \file test_malloc_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 
33*ab7f370cSPavel Kumbrasev // There is no RLIMIT_AS on OpenBSD.
34*ab7f370cSPavel Kumbrasev // Therefore, the tests for memory limit is unreasonable.
35*ab7f370cSPavel Kumbrasev #if !__OpenBSD__
36*ab7f370cSPavel Kumbrasev 
3751c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1
3851c0b2f7Stbbdev #include "tbb/scalable_allocator.h"
3951c0b2f7Stbbdev 
4051c0b2f7Stbbdev #include <vector>
4151c0b2f7Stbbdev 
4251c0b2f7Stbbdev #if _WIN32 || _WIN64
4351c0b2f7Stbbdev /**
4451c0b2f7Stbbdev  *  _WIN32_WINNT should be defined at the very beginning,
4551c0b2f7Stbbdev  *  because other headers might include <windows.h>
4651c0b2f7Stbbdev  **/
4751c0b2f7Stbbdev #undef _WIN32_WINNT
4851c0b2f7Stbbdev #define _WIN32_WINNT 0x0501
4951c0b2f7Stbbdev #include <windows.h>
5051c0b2f7Stbbdev #include <stdio.h>
5151c0b2f7Stbbdev 
5251c0b2f7Stbbdev #if _MSC_VER && defined(_MT) && defined(_DLL)
5351c0b2f7Stbbdev     #pragma comment(lib, "version.lib")  // to use GetFileVersionInfo*
5451c0b2f7Stbbdev #endif
5551c0b2f7Stbbdev 
limitMem(size_t limit)5651c0b2f7Stbbdev void limitMem( size_t limit )
5751c0b2f7Stbbdev {
5857f524caSIlya Isaev     static HANDLE hJob = nullptr;
5951c0b2f7Stbbdev     JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;
6051c0b2f7Stbbdev 
6151c0b2f7Stbbdev     jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
6251c0b2f7Stbbdev     jobInfo.ProcessMemoryLimit = limit? limit*MByte : 2*MByte*1024;
6357f524caSIlya Isaev     if (nullptr == hJob) {
6457f524caSIlya Isaev         if (nullptr == (hJob = CreateJobObject(nullptr, nullptr))) {
6551c0b2f7Stbbdev             REPORT("Can't assign create job object: %ld\n", GetLastError());
6651c0b2f7Stbbdev             exit(1);
6751c0b2f7Stbbdev         }
6851c0b2f7Stbbdev         if (0 == AssignProcessToJobObject(hJob, GetCurrentProcess())) {
6951c0b2f7Stbbdev             REPORT("Can't assign process to job object: %ld\n", GetLastError());
7051c0b2f7Stbbdev             exit(1);
7151c0b2f7Stbbdev         }
7251c0b2f7Stbbdev     }
7351c0b2f7Stbbdev     if (0 == SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
7451c0b2f7Stbbdev                                      &jobInfo, sizeof(jobInfo))) {
7551c0b2f7Stbbdev         REPORT("Can't set limits: %ld\n", GetLastError());
7651c0b2f7Stbbdev         exit(1);
7751c0b2f7Stbbdev     }
7851c0b2f7Stbbdev }
7951c0b2f7Stbbdev // Do not test errno with static VC runtime
8051c0b2f7Stbbdev #else // _WIN32 || _WIN64
8151c0b2f7Stbbdev #include <sys/resource.h>
8251c0b2f7Stbbdev #include <stdlib.h>
8351c0b2f7Stbbdev #include <stdio.h>
8451c0b2f7Stbbdev #include <errno.h>
8551c0b2f7Stbbdev #include <sys/types.h>  // uint64_t on FreeBSD, needed for rlim_t
8651c0b2f7Stbbdev #include <stdint.h>     // SIZE_MAX
8751c0b2f7Stbbdev 
limitMem(size_t limit)8851c0b2f7Stbbdev void limitMem( size_t limit )
8951c0b2f7Stbbdev {
9051c0b2f7Stbbdev     rlimit rlim;
9151c0b2f7Stbbdev     int ret = getrlimit(RLIMIT_AS,&rlim);
9251c0b2f7Stbbdev     if (0 != ret) {
9351c0b2f7Stbbdev         REPORT("getrlimit() returned an error: errno %d\n", errno);
9451c0b2f7Stbbdev         exit(1);
9551c0b2f7Stbbdev     }
9651c0b2f7Stbbdev     if (rlim.rlim_max==(rlim_t)RLIM_INFINITY)
9751c0b2f7Stbbdev         rlim.rlim_cur = (limit > 0) ? limit*MByte : rlim.rlim_max;
98a3151ce8SIvan Kochin     else rlim.rlim_cur = (limit > 0 && static_cast<rlim_t>(limit)<rlim.rlim_max) ? limit*MByte : rlim.rlim_max;
9951c0b2f7Stbbdev     ret = setrlimit(RLIMIT_AS,&rlim);
10051c0b2f7Stbbdev     if (0 != ret) {
10151c0b2f7Stbbdev         REPORT("Can't set limits: errno %d\n", errno);
10251c0b2f7Stbbdev         exit(1);
10351c0b2f7Stbbdev     }
10451c0b2f7Stbbdev }
10551c0b2f7Stbbdev #endif  // _WIN32 || _WIN64
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev bool __tbb_test_errno = false;
10851c0b2f7Stbbdev 
10951c0b2f7Stbbdev #define ASSERT_ERRNO(cond, msg)  REQUIRE_MESSAGE( (!__tbb_test_errno || (cond)), msg )
11051c0b2f7Stbbdev #define CHECK_ERRNO(cond) (__tbb_test_errno && (cond))
11151c0b2f7Stbbdev 
11251c0b2f7Stbbdev static const int MinThread = 1;
11351c0b2f7Stbbdev static const int MaxThread = 4;
11451c0b2f7Stbbdev static bool Verbose = false;
11551c0b2f7Stbbdev 
11651c0b2f7Stbbdev #include <time.h>
11751c0b2f7Stbbdev #include <errno.h>
11851c0b2f7Stbbdev #include <limits.h> // for CHAR_BIT
11951c0b2f7Stbbdev 
120734f0bc0SPablo Romero #if __unix__
12151c0b2f7Stbbdev #include <stdint.h> // uintptr_t
12251c0b2f7Stbbdev #endif
12351c0b2f7Stbbdev #if _WIN32 || _WIN64
12451c0b2f7Stbbdev #include <malloc.h> // _aligned_(malloc|free|realloc)
12551c0b2f7Stbbdev #if __MINGW64__
12651c0b2f7Stbbdev // Workaround a bug in MinGW64 headers with _aligned_(malloc|free) not declared by default
1278827ea7dSLong Nguyen extern "C" void __cdecl __declspec(dllimport) _aligned_free(void *);
1288827ea7dSLong Nguyen extern "C" void *__cdecl __declspec(dllimport) _aligned_malloc(size_t,size_t);
12951c0b2f7Stbbdev #endif
13051c0b2f7Stbbdev #endif
13151c0b2f7Stbbdev 
13251c0b2f7Stbbdev #include <vector>
13351c0b2f7Stbbdev 
13451c0b2f7Stbbdev const int COUNT_ELEM = 25000;
13551c0b2f7Stbbdev const size_t MAX_SIZE = 1000;
13651c0b2f7Stbbdev const int COUNTEXPERIMENT = 10000;
13751c0b2f7Stbbdev 
13851c0b2f7Stbbdev const char strError[]="failed";
13951c0b2f7Stbbdev const char strOk[]="done";
14051c0b2f7Stbbdev 
14151c0b2f7Stbbdev typedef unsigned int UINT;
14251c0b2f7Stbbdev typedef unsigned char UCHAR;
14351c0b2f7Stbbdev typedef unsigned long DWORD;
14451c0b2f7Stbbdev typedef unsigned char BYTE;
14551c0b2f7Stbbdev 
14651c0b2f7Stbbdev typedef void* TestMalloc(size_t size);
14751c0b2f7Stbbdev typedef void* TestCalloc(size_t num, size_t size);
14851c0b2f7Stbbdev typedef void* TestRealloc(void* memblock, size_t size);
14951c0b2f7Stbbdev typedef void  TestFree(void* memblock);
15051c0b2f7Stbbdev typedef int   TestPosixMemalign(void **memptr, size_t alignment, size_t size);
15151c0b2f7Stbbdev typedef void* TestAlignedMalloc(size_t size, size_t alignment);
15251c0b2f7Stbbdev typedef void* TestAlignedRealloc(void* memblock, size_t size, size_t alignment);
15351c0b2f7Stbbdev typedef void  TestAlignedFree(void* memblock);
15451c0b2f7Stbbdev 
15551c0b2f7Stbbdev // pointers to tested functions
15651c0b2f7Stbbdev TestMalloc*  Rmalloc;
15751c0b2f7Stbbdev TestCalloc*  Rcalloc;
15851c0b2f7Stbbdev TestRealloc* Rrealloc;
15951c0b2f7Stbbdev TestFree*    Tfree;
16051c0b2f7Stbbdev TestPosixMemalign*  Rposix_memalign;
16151c0b2f7Stbbdev TestAlignedMalloc*  Raligned_malloc;
16251c0b2f7Stbbdev TestAlignedRealloc* Raligned_realloc;
16351c0b2f7Stbbdev TestAlignedFree* Taligned_free;
16451c0b2f7Stbbdev 
16551c0b2f7Stbbdev // call functions via pointer and check result's alignment
16651c0b2f7Stbbdev void* Tmalloc(size_t size);
16751c0b2f7Stbbdev void* Tcalloc(size_t num, size_t size);
16851c0b2f7Stbbdev void* Trealloc(void* memblock, size_t size);
16951c0b2f7Stbbdev int   Tposix_memalign(void **memptr, size_t alignment, size_t size);
17051c0b2f7Stbbdev void* Taligned_malloc(size_t size, size_t alignment);
17151c0b2f7Stbbdev void* Taligned_realloc(void* memblock, size_t size, size_t alignment);
17251c0b2f7Stbbdev 
173a080baf9SAlex std::atomic<bool> error_occurred{ false };
17451c0b2f7Stbbdev 
17551c0b2f7Stbbdev #if __APPLE__
17651c0b2f7Stbbdev // Tests that use the variables are skipped on macOS*
17751c0b2f7Stbbdev #else
17851c0b2f7Stbbdev const size_t COUNT_ELEM_CALLOC = 2;
17951c0b2f7Stbbdev const int COUNT_TESTS = 1000;
18051c0b2f7Stbbdev static bool perProcessLimits = true;
18151c0b2f7Stbbdev #endif
18251c0b2f7Stbbdev 
18351c0b2f7Stbbdev const size_t POWERS_OF_2 = 20;
18451c0b2f7Stbbdev 
18551c0b2f7Stbbdev struct MemStruct
18651c0b2f7Stbbdev {
18751c0b2f7Stbbdev     void* Pointer;
18851c0b2f7Stbbdev     UINT Size;
18951c0b2f7Stbbdev 
MemStructMemStruct19057f524caSIlya Isaev     MemStruct() : Pointer(nullptr), Size(0) {}
MemStructMemStruct19151c0b2f7Stbbdev     MemStruct(void* ptr, UINT sz) : Pointer(ptr), Size(sz) {}
19251c0b2f7Stbbdev };
19351c0b2f7Stbbdev 
19451c0b2f7Stbbdev class CMemTest: utils::NoAssign
19551c0b2f7Stbbdev {
19651c0b2f7Stbbdev     bool FullLog;
19751c0b2f7Stbbdev     utils::SpinBarrier *limitBarrier;
19851c0b2f7Stbbdev     static bool firstTime;
19951c0b2f7Stbbdev 
20051c0b2f7Stbbdev public:
CMemTest(utils::SpinBarrier * barrier,bool isVerbose=false)201a080baf9SAlex     CMemTest(utils::SpinBarrier *barrier, bool isVerbose=false) : limitBarrier(barrier)
20251c0b2f7Stbbdev         {
20357f524caSIlya Isaev             srand((UINT)time(nullptr));
20451c0b2f7Stbbdev             FullLog=isVerbose;
20551c0b2f7Stbbdev         }
20657f524caSIlya Isaev     void NULLReturn(UINT MinSize, UINT MaxSize, int total_threads); // nullptr pointer + check errno
20751c0b2f7Stbbdev     void UniquePointer(); // unique pointer - check with padding
20851c0b2f7Stbbdev     void AddrArifm(); // unique pointer - check with pointer arithmetic
20951c0b2f7Stbbdev     bool ShouldReportError();
21051c0b2f7Stbbdev     void Free_NULL(); //
21151c0b2f7Stbbdev     void Zerofilling(); // check if arrays are zero-filled
21251c0b2f7Stbbdev     void TestAlignedParameters();
21351c0b2f7Stbbdev     void RunAllTests(int total_threads);
~CMemTest()21451c0b2f7Stbbdev     ~CMemTest() {}
21551c0b2f7Stbbdev };
21651c0b2f7Stbbdev 
21751c0b2f7Stbbdev class Limit {
21851c0b2f7Stbbdev     size_t limit;
21951c0b2f7Stbbdev public:
Limit(size_t a_limit)22051c0b2f7Stbbdev     Limit(size_t a_limit) : limit(a_limit) {}
operator ()() const22151c0b2f7Stbbdev     void operator() () const {
22251c0b2f7Stbbdev         limitMem(limit);
22351c0b2f7Stbbdev     }
22451c0b2f7Stbbdev };
22551c0b2f7Stbbdev 
22651c0b2f7Stbbdev int argC;
22751c0b2f7Stbbdev char** argV;
22851c0b2f7Stbbdev 
22951c0b2f7Stbbdev struct RoundRobin: utils::NoAssign {
23051c0b2f7Stbbdev     const long number_of_threads;
23151c0b2f7Stbbdev     mutable CMemTest test;
23251c0b2f7Stbbdev 
RoundRobinRoundRobin23351c0b2f7Stbbdev     RoundRobin( long p, utils::SpinBarrier *limitBarrier, bool verbose ) :
23451c0b2f7Stbbdev         number_of_threads(p), test(limitBarrier, verbose) {}
operator ()RoundRobin23551c0b2f7Stbbdev     void operator()( int /*id*/ ) const
23651c0b2f7Stbbdev         {
23751c0b2f7Stbbdev             test.RunAllTests(number_of_threads);
23851c0b2f7Stbbdev         }
23951c0b2f7Stbbdev };
24051c0b2f7Stbbdev 
24151c0b2f7Stbbdev bool CMemTest::firstTime = true;
24251c0b2f7Stbbdev 
choose_random_alignment()24351c0b2f7Stbbdev inline size_t choose_random_alignment() {
24451c0b2f7Stbbdev     return sizeof(void*)<<(rand() % POWERS_OF_2);
24551c0b2f7Stbbdev }
24651c0b2f7Stbbdev 
24751c0b2f7Stbbdev #if TBB_REVAMP_TODO
24851c0b2f7Stbbdev // TODO: enable this test mode
setSystemAllocs()24951c0b2f7Stbbdev static void setSystemAllocs()
25051c0b2f7Stbbdev {
25151c0b2f7Stbbdev     Rmalloc=malloc;
25251c0b2f7Stbbdev     Rrealloc=realloc;
25351c0b2f7Stbbdev     Rcalloc=calloc;
25451c0b2f7Stbbdev     Tfree=free;
25551c0b2f7Stbbdev #if _WIN32 || _WIN64
25651c0b2f7Stbbdev     Raligned_malloc=_aligned_malloc;
25751c0b2f7Stbbdev     Raligned_realloc=_aligned_realloc;
25851c0b2f7Stbbdev     Taligned_free=_aligned_free;
25951c0b2f7Stbbdev     Rposix_memalign=0;
26051c0b2f7Stbbdev #elif  __APPLE__ || __sun || __ANDROID__
26151c0b2f7Stbbdev // macOS, Solaris*, and Android* don't have posix_memalign
26251c0b2f7Stbbdev     Raligned_malloc=0;
26351c0b2f7Stbbdev     Raligned_realloc=0;
26451c0b2f7Stbbdev     Taligned_free=0;
26551c0b2f7Stbbdev     Rposix_memalign=0;
26651c0b2f7Stbbdev #else
26751c0b2f7Stbbdev     Raligned_malloc=0;
26851c0b2f7Stbbdev     Raligned_realloc=0;
26951c0b2f7Stbbdev     Taligned_free=0;
27051c0b2f7Stbbdev     Rposix_memalign=posix_memalign;
27151c0b2f7Stbbdev #endif
27251c0b2f7Stbbdev }
27351c0b2f7Stbbdev #endif
27451c0b2f7Stbbdev 
27551c0b2f7Stbbdev // check that realloc works as free and as malloc
ReallocParam()27651c0b2f7Stbbdev void ReallocParam()
27751c0b2f7Stbbdev {
27851c0b2f7Stbbdev     const int ITERS = 1000;
27951c0b2f7Stbbdev     int i;
28051c0b2f7Stbbdev     void *bufs[ITERS];
28151c0b2f7Stbbdev 
28257f524caSIlya Isaev     bufs[0] = Trealloc(nullptr, 30*MByte);
28351c0b2f7Stbbdev     REQUIRE_MESSAGE(bufs[0], "Can't get memory to start the test.");
28451c0b2f7Stbbdev 
28551c0b2f7Stbbdev     for (i=1; i<ITERS; i++)
28651c0b2f7Stbbdev     {
28757f524caSIlya Isaev         bufs[i] = Trealloc(nullptr, 30*MByte);
28857f524caSIlya Isaev         if (nullptr == bufs[i])
28951c0b2f7Stbbdev             break;
29051c0b2f7Stbbdev     }
29151c0b2f7Stbbdev     REQUIRE_MESSAGE(i<ITERS, "Limits should be decreased for the test to work.");
29251c0b2f7Stbbdev 
29351c0b2f7Stbbdev     Trealloc(bufs[0], 0);
29451c0b2f7Stbbdev     /* There is a race for the free space between different threads at
29551c0b2f7Stbbdev        this point. So, have to run the test sequentially.
29651c0b2f7Stbbdev     */
29757f524caSIlya Isaev     bufs[0] = Trealloc(nullptr, 30*MByte);
29851c0b2f7Stbbdev     REQUIRE(bufs[0]);
29951c0b2f7Stbbdev 
30051c0b2f7Stbbdev     for (int j=0; j<i; j++)
30151c0b2f7Stbbdev         Trealloc(bufs[j], 0);
30251c0b2f7Stbbdev }
30351c0b2f7Stbbdev 
CheckArgumentsOverflow()30451c0b2f7Stbbdev void CheckArgumentsOverflow()
30551c0b2f7Stbbdev {
30651c0b2f7Stbbdev     void *p;
30751c0b2f7Stbbdev     const size_t params[] = {SIZE_MAX, SIZE_MAX-16};
30851c0b2f7Stbbdev 
30951c0b2f7Stbbdev     for (unsigned i=0; i<utils::array_length(params); i++) {
31051c0b2f7Stbbdev         p = Tmalloc(params[i]);
31151c0b2f7Stbbdev         REQUIRE(!p);
31257f524caSIlya Isaev         ASSERT_ERRNO(errno==ENOMEM, nullptr);
31357f524caSIlya Isaev         p = Trealloc(nullptr, params[i]);
31451c0b2f7Stbbdev         REQUIRE(!p);
31557f524caSIlya Isaev         ASSERT_ERRNO(errno==ENOMEM, nullptr);
31651c0b2f7Stbbdev         p = Tcalloc(1, params[i]);
31751c0b2f7Stbbdev         REQUIRE(!p);
31857f524caSIlya Isaev         ASSERT_ERRNO(errno==ENOMEM, nullptr);
31951c0b2f7Stbbdev         p = Tcalloc(params[i], 1);
32051c0b2f7Stbbdev         REQUIRE(!p);
32157f524caSIlya Isaev         ASSERT_ERRNO(errno==ENOMEM, nullptr);
32251c0b2f7Stbbdev     }
32351c0b2f7Stbbdev     const size_t max_alignment = size_t(1) << (sizeof(size_t)*CHAR_BIT - 1);
32451c0b2f7Stbbdev     if (Rposix_memalign) {
32551c0b2f7Stbbdev         int ret = Rposix_memalign(&p, max_alignment, ~max_alignment);
32651c0b2f7Stbbdev         REQUIRE(ret == ENOMEM);
32751c0b2f7Stbbdev         for (unsigned i=0; i<utils::array_length(params); i++) {
32851c0b2f7Stbbdev             ret = Rposix_memalign(&p, max_alignment, params[i]);
32951c0b2f7Stbbdev             REQUIRE(ret == ENOMEM);
33051c0b2f7Stbbdev             ret = Rposix_memalign(&p, sizeof(void*), params[i]);
33151c0b2f7Stbbdev             REQUIRE(ret == ENOMEM);
33251c0b2f7Stbbdev         }
33351c0b2f7Stbbdev     }
33451c0b2f7Stbbdev     if (Raligned_malloc) {
33551c0b2f7Stbbdev         p = Raligned_malloc(~max_alignment, max_alignment);
33651c0b2f7Stbbdev         REQUIRE(!p);
33751c0b2f7Stbbdev         for (unsigned i=0; i<utils::array_length(params); i++) {
33851c0b2f7Stbbdev             p = Raligned_malloc(params[i], max_alignment);
33951c0b2f7Stbbdev             REQUIRE(!p);
34057f524caSIlya Isaev             ASSERT_ERRNO(errno==ENOMEM, nullptr);
34151c0b2f7Stbbdev             p = Raligned_malloc(params[i], sizeof(void*));
34251c0b2f7Stbbdev             REQUIRE(!p);
34357f524caSIlya Isaev             ASSERT_ERRNO(errno==ENOMEM, nullptr);
34451c0b2f7Stbbdev         }
34551c0b2f7Stbbdev     }
34651c0b2f7Stbbdev 
34751c0b2f7Stbbdev     p = Tcalloc(SIZE_MAX/2-16, SIZE_MAX/2-16);
34851c0b2f7Stbbdev     REQUIRE(!p);
34957f524caSIlya Isaev     ASSERT_ERRNO(errno==ENOMEM, nullptr);
35051c0b2f7Stbbdev     p = Tcalloc(SIZE_MAX/2, SIZE_MAX/2);
35151c0b2f7Stbbdev     REQUIRE(!p);
35257f524caSIlya Isaev     ASSERT_ERRNO(errno==ENOMEM, nullptr);
35351c0b2f7Stbbdev }
35451c0b2f7Stbbdev 
InvariantDataRealloc(bool aligned,size_t maxAllocSize,bool checkData)35551c0b2f7Stbbdev void InvariantDataRealloc(bool aligned, size_t maxAllocSize, bool checkData)
35651c0b2f7Stbbdev {
35751c0b2f7Stbbdev     utils::FastRandom<> fastRandom(1);
35851c0b2f7Stbbdev     size_t size = 0, start = 0;
35957f524caSIlya Isaev     char *ptr = nullptr,
360b15aabb3Stbbdev         // external thread to create copies and compare ralloc result against it
3611ecde27fSIlya Mishin         *base = (char*)Tmalloc(2*maxAllocSize);
36251c0b2f7Stbbdev 
3631ecde27fSIlya Mishin     REQUIRE(base);
36451c0b2f7Stbbdev     REQUIRE_MESSAGE(!(2*maxAllocSize%sizeof(unsigned short)),
36551c0b2f7Stbbdev            "The loop below expects that 2*maxAllocSize contains sizeof(unsigned short)");
36651c0b2f7Stbbdev     for (size_t k = 0; k<2*maxAllocSize; k+=sizeof(unsigned short))
3671ecde27fSIlya Mishin         *(unsigned short*)(base+k) = fastRandom.get();
36851c0b2f7Stbbdev 
36951c0b2f7Stbbdev     for (int i=0; i<100; i++) {
37051c0b2f7Stbbdev         // don't want sizeNew==0 here
37151c0b2f7Stbbdev         const size_t sizeNew = fastRandom.get() % (maxAllocSize-1) + 1;
37251c0b2f7Stbbdev         char *ptrNew = aligned?
37351c0b2f7Stbbdev             (char*)Taligned_realloc(ptr, sizeNew, choose_random_alignment())
37451c0b2f7Stbbdev             : (char*)Trealloc(ptr, sizeNew);
37551c0b2f7Stbbdev         REQUIRE(ptrNew);
37651c0b2f7Stbbdev         // check that old data not changed
37751c0b2f7Stbbdev         if (checkData)
3781ecde27fSIlya Mishin             REQUIRE_MESSAGE(!memcmp(ptrNew, base+start, utils::min(size, sizeNew)), "broken data");
37951c0b2f7Stbbdev 
380b15aabb3Stbbdev         // prepare fresh data, copying them from random position in external
38151c0b2f7Stbbdev         size = sizeNew;
38251c0b2f7Stbbdev         ptr = ptrNew;
38351c0b2f7Stbbdev         if (checkData) {
38451c0b2f7Stbbdev             start = fastRandom.get() % maxAllocSize;
3851ecde27fSIlya Mishin             memcpy(ptr, base+start, size);
38651c0b2f7Stbbdev         }
38751c0b2f7Stbbdev     }
38851c0b2f7Stbbdev     if (aligned)
38951c0b2f7Stbbdev         Taligned_realloc(ptr, 0, choose_random_alignment());
39051c0b2f7Stbbdev     else
39151c0b2f7Stbbdev         Trealloc(ptr, 0);
3921ecde27fSIlya Mishin     Tfree(base);
39351c0b2f7Stbbdev }
39451c0b2f7Stbbdev 
CheckReallocLeak()39551c0b2f7Stbbdev void CheckReallocLeak()
39651c0b2f7Stbbdev {
39751c0b2f7Stbbdev     int i;
39851c0b2f7Stbbdev     const int ITER_TO_STABILITY = 10;
39951c0b2f7Stbbdev     // do bootstrap
40051c0b2f7Stbbdev     for (int k=0; k<3; k++)
40151c0b2f7Stbbdev         InvariantDataRealloc(/*aligned=*/false, 128*MByte, /*checkData=*/false);
40251c0b2f7Stbbdev     size_t prev = utils::GetMemoryUsage(utils::peakUsage);
40351c0b2f7Stbbdev     // expect realloc to not increase peak memory consumption after ITER_TO_STABILITY-1 iterations
40451c0b2f7Stbbdev     for (i=0; i<ITER_TO_STABILITY; i++) {
40551c0b2f7Stbbdev         for (int k=0; k<3; k++)
40651c0b2f7Stbbdev             InvariantDataRealloc(/*aligned=*/false, 128*MByte, /*checkData=*/false);
40751c0b2f7Stbbdev         size_t curr = utils::GetMemoryUsage(utils::peakUsage);
40851c0b2f7Stbbdev         if (prev == curr)
40951c0b2f7Stbbdev             break;
41051c0b2f7Stbbdev         prev = curr;
41151c0b2f7Stbbdev     }
41251c0b2f7Stbbdev     REQUIRE_MESSAGE(i < ITER_TO_STABILITY, "Can't stabilize memory consumption.");
41351c0b2f7Stbbdev }
41451c0b2f7Stbbdev 
41551c0b2f7Stbbdev // if non-zero byte found, returns bad value address plus 1
NonZero(void * ptr,size_t size)41651c0b2f7Stbbdev size_t NonZero(void *ptr, size_t size)
41751c0b2f7Stbbdev {
41851c0b2f7Stbbdev     size_t words = size / sizeof(intptr_t);
41951c0b2f7Stbbdev     size_t tailSz = size % sizeof(intptr_t);
42051c0b2f7Stbbdev     intptr_t *buf =(intptr_t*)ptr;
42151c0b2f7Stbbdev     char *bufTail =(char*)(buf+words);
42251c0b2f7Stbbdev 
42351c0b2f7Stbbdev     for (size_t i=0; i<words; i++)
42451c0b2f7Stbbdev         if (buf[i]) {
42551c0b2f7Stbbdev             for (unsigned b=0; b<sizeof(intptr_t); b++)
42651c0b2f7Stbbdev                 if (((char*)(buf+i))[b])
42751c0b2f7Stbbdev                     return sizeof(intptr_t)*i + b + 1;
42851c0b2f7Stbbdev         }
42951c0b2f7Stbbdev     for (size_t i=0; i<tailSz; i++)
43051c0b2f7Stbbdev         if (bufTail[i]) {
43151c0b2f7Stbbdev             return words*sizeof(intptr_t)+i+1;
43251c0b2f7Stbbdev         }
43351c0b2f7Stbbdev     return 0;
43451c0b2f7Stbbdev }
43551c0b2f7Stbbdev 
43651c0b2f7Stbbdev struct TestStruct
43751c0b2f7Stbbdev {
43851c0b2f7Stbbdev     DWORD field1:2;
43951c0b2f7Stbbdev     DWORD field2:6;
44051c0b2f7Stbbdev     double field3;
44151c0b2f7Stbbdev     UCHAR field4[100];
44251c0b2f7Stbbdev     TestStruct* field5;
44351c0b2f7Stbbdev     std::vector<int> field7;
44451c0b2f7Stbbdev     double field8;
44551c0b2f7Stbbdev };
44651c0b2f7Stbbdev 
Tmalloc(size_t size)44751c0b2f7Stbbdev void* Tmalloc(size_t size)
44851c0b2f7Stbbdev {
44951c0b2f7Stbbdev     // For compatibility, on 64-bit systems malloc should align to 16 bytes
45051c0b2f7Stbbdev     size_t alignment = (sizeof(intptr_t)>4 && size>8) ? 16 : 8;
45151c0b2f7Stbbdev     void *ret = Rmalloc(size);
45257f524caSIlya Isaev     if (nullptr != ret)
453a080baf9SAlex         CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)),
45451c0b2f7Stbbdev                "allocation result should be properly aligned");
45551c0b2f7Stbbdev     return ret;
45651c0b2f7Stbbdev }
Tcalloc(size_t num,size_t size)45751c0b2f7Stbbdev void* Tcalloc(size_t num, size_t size)
45851c0b2f7Stbbdev {
45951c0b2f7Stbbdev     // For compatibility, on 64-bit systems calloc should align to 16 bytes
46051c0b2f7Stbbdev     size_t alignment = (sizeof(intptr_t)>4 && num && size>8) ? 16 : 8;
46151c0b2f7Stbbdev     void *ret = Rcalloc(num, size);
46257f524caSIlya Isaev     if (nullptr != ret)
463a080baf9SAlex         CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)),
46451c0b2f7Stbbdev                "allocation result should be properly aligned");
46551c0b2f7Stbbdev     return ret;
46651c0b2f7Stbbdev }
Trealloc(void * memblock,size_t size)46751c0b2f7Stbbdev void* Trealloc(void* memblock, size_t size)
46851c0b2f7Stbbdev {
46951c0b2f7Stbbdev     // For compatibility, on 64-bit systems realloc should align to 16 bytes
47051c0b2f7Stbbdev     size_t alignment = (sizeof(intptr_t)>4 && size>8) ? 16 : 8;
47151c0b2f7Stbbdev     void *ret = Rrealloc(memblock, size);
47257f524caSIlya Isaev     if (nullptr != ret)
473a080baf9SAlex         CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)),
47451c0b2f7Stbbdev                "allocation result should be properly aligned");
47551c0b2f7Stbbdev     return ret;
47651c0b2f7Stbbdev }
Tposix_memalign(void ** memptr,size_t alignment,size_t size)47751c0b2f7Stbbdev int Tposix_memalign(void **memptr, size_t alignment, size_t size)
47851c0b2f7Stbbdev {
47951c0b2f7Stbbdev     int ret = Rposix_memalign(memptr, alignment, size);
48051c0b2f7Stbbdev     if (0 == ret)
481a080baf9SAlex         CHECK_FAST_MESSAGE(0==((uintptr_t)*memptr & (alignment-1)),
48251c0b2f7Stbbdev                "allocation result should be aligned");
48351c0b2f7Stbbdev     return ret;
48451c0b2f7Stbbdev }
Taligned_malloc(size_t size,size_t alignment)48551c0b2f7Stbbdev void* Taligned_malloc(size_t size, size_t alignment)
48651c0b2f7Stbbdev {
48751c0b2f7Stbbdev     void *ret = Raligned_malloc(size, alignment);
48857f524caSIlya Isaev     if (nullptr != ret)
489a080baf9SAlex         CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)),
49051c0b2f7Stbbdev                "allocation result should be aligned");
49151c0b2f7Stbbdev     return ret;
49251c0b2f7Stbbdev }
Taligned_realloc(void * memblock,size_t size,size_t alignment)49351c0b2f7Stbbdev void* Taligned_realloc(void* memblock, size_t size, size_t alignment)
49451c0b2f7Stbbdev {
49551c0b2f7Stbbdev     void *ret = Raligned_realloc(memblock, size, alignment);
49657f524caSIlya Isaev     if (nullptr != ret)
497a080baf9SAlex         CHECK_FAST_MESSAGE(0==((uintptr_t)ret & (alignment-1)),
49851c0b2f7Stbbdev                "allocation result should be aligned");
49951c0b2f7Stbbdev     return ret;
50051c0b2f7Stbbdev }
50151c0b2f7Stbbdev 
50251c0b2f7Stbbdev struct PtrSize {
50351c0b2f7Stbbdev     void  *ptr;
50451c0b2f7Stbbdev     size_t size;
50551c0b2f7Stbbdev };
50651c0b2f7Stbbdev 
cmpAddrs(const void * p1,const void * p2)50751c0b2f7Stbbdev static int cmpAddrs(const void *p1, const void *p2)
50851c0b2f7Stbbdev {
50951c0b2f7Stbbdev     const PtrSize *a = (const PtrSize *)p1;
51051c0b2f7Stbbdev     const PtrSize *b = (const PtrSize *)p2;
51151c0b2f7Stbbdev 
51251c0b2f7Stbbdev     return a->ptr < b->ptr ? -1 : ( a->ptr == b->ptr ? 0 : 1);
51351c0b2f7Stbbdev }
51451c0b2f7Stbbdev 
AddrArifm()51551c0b2f7Stbbdev void CMemTest::AddrArifm()
51651c0b2f7Stbbdev {
51751c0b2f7Stbbdev     PtrSize *arr = (PtrSize*)Tmalloc(COUNT_ELEM*sizeof(PtrSize));
51851c0b2f7Stbbdev 
51951c0b2f7Stbbdev     if (FullLog) REPORT("\nUnique pointer using Address arithmetic\n");
52051c0b2f7Stbbdev     if (FullLog) REPORT("malloc....");
52151c0b2f7Stbbdev     REQUIRE(arr);
52251c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
52351c0b2f7Stbbdev     {
52451c0b2f7Stbbdev         arr[i].size=rand()%MAX_SIZE;
52551c0b2f7Stbbdev         arr[i].ptr=Tmalloc(arr[i].size);
52651c0b2f7Stbbdev     }
52751c0b2f7Stbbdev     qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs);
52851c0b2f7Stbbdev 
52951c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM-1; i++)
53051c0b2f7Stbbdev     {
53157f524caSIlya Isaev         if (nullptr!=arr[i].ptr && nullptr!=arr[i+1].ptr)
53251c0b2f7Stbbdev             REQUIRE_MESSAGE((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr,
53351c0b2f7Stbbdev                    "intersection detected");
53451c0b2f7Stbbdev     }
53551c0b2f7Stbbdev     //----------------------------------------------------------------
53651c0b2f7Stbbdev     if (FullLog) REPORT("realloc....");
53751c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
53851c0b2f7Stbbdev     {
53951c0b2f7Stbbdev         size_t count=arr[i].size*2;
54051c0b2f7Stbbdev         void *tmpAddr=Trealloc(arr[i].ptr,count);
54157f524caSIlya Isaev         if (nullptr!=tmpAddr) {
54251c0b2f7Stbbdev             arr[i].ptr = tmpAddr;
54351c0b2f7Stbbdev             arr[i].size = count;
54451c0b2f7Stbbdev         } else if (count==0) { // because realloc(..., 0) works as free
54557f524caSIlya Isaev             arr[i].ptr = nullptr;
54651c0b2f7Stbbdev             arr[i].size = 0;
54751c0b2f7Stbbdev         }
54851c0b2f7Stbbdev     }
54951c0b2f7Stbbdev     qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs);
55051c0b2f7Stbbdev 
55151c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM-1; i++)
55251c0b2f7Stbbdev     {
55357f524caSIlya Isaev         if (nullptr!=arr[i].ptr && nullptr!=arr[i+1].ptr)
55451c0b2f7Stbbdev             REQUIRE_MESSAGE((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr,
55551c0b2f7Stbbdev                    "intersection detected");
55651c0b2f7Stbbdev     }
55751c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
55851c0b2f7Stbbdev     {
55951c0b2f7Stbbdev         Tfree(arr[i].ptr);
56051c0b2f7Stbbdev     }
56151c0b2f7Stbbdev     //-------------------------------------------
56251c0b2f7Stbbdev     if (FullLog) REPORT("calloc....");
56351c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
56451c0b2f7Stbbdev     {
56551c0b2f7Stbbdev         arr[i].size=rand()%MAX_SIZE;
56651c0b2f7Stbbdev         arr[i].ptr=Tcalloc(arr[i].size,1);
56751c0b2f7Stbbdev     }
56851c0b2f7Stbbdev     qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs);
56951c0b2f7Stbbdev 
57051c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM-1; i++)
57151c0b2f7Stbbdev     {
57257f524caSIlya Isaev         if (nullptr!=arr[i].ptr && nullptr!=arr[i+1].ptr)
57351c0b2f7Stbbdev             REQUIRE_MESSAGE((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr,
57451c0b2f7Stbbdev                    "intersection detected");
57551c0b2f7Stbbdev     }
57651c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
57751c0b2f7Stbbdev     {
57851c0b2f7Stbbdev         Tfree(arr[i].ptr);
57951c0b2f7Stbbdev     }
58051c0b2f7Stbbdev     Tfree(arr);
58151c0b2f7Stbbdev }
58251c0b2f7Stbbdev 
Zerofilling()58351c0b2f7Stbbdev void CMemTest::Zerofilling()
58451c0b2f7Stbbdev {
58551c0b2f7Stbbdev     TestStruct* TSMas;
58651c0b2f7Stbbdev     size_t CountElement;
587a080baf9SAlex     static std::atomic<int> CountErrors{0};
58851c0b2f7Stbbdev     if (FullLog) REPORT("\nzeroings elements of array....");
58951c0b2f7Stbbdev     //test struct
59051c0b2f7Stbbdev     for (int i=0; i<COUNTEXPERIMENT; i++)
59151c0b2f7Stbbdev     {
59251c0b2f7Stbbdev         CountElement=rand()%MAX_SIZE;
59351c0b2f7Stbbdev         TSMas=(TestStruct*)Tcalloc(CountElement,sizeof(TestStruct));
59457f524caSIlya Isaev         if (nullptr == TSMas)
59551c0b2f7Stbbdev             continue;
59651c0b2f7Stbbdev         for (size_t j=0; j<CountElement; j++)
59751c0b2f7Stbbdev         {
59851c0b2f7Stbbdev             if (NonZero(TSMas+j, sizeof(TestStruct)))
59951c0b2f7Stbbdev             {
60051c0b2f7Stbbdev                 CountErrors++;
60151c0b2f7Stbbdev                 if (ShouldReportError()) REPORT("detect nonzero element at TestStruct\n");
60251c0b2f7Stbbdev             }
60351c0b2f7Stbbdev         }
60451c0b2f7Stbbdev         Tfree(TSMas);
60551c0b2f7Stbbdev     }
60651c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
60751c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
608a080baf9SAlex     if (CountErrors) error_occurred = true;
60951c0b2f7Stbbdev }
61051c0b2f7Stbbdev 
61151c0b2f7Stbbdev #if !__APPLE__
61251c0b2f7Stbbdev 
myMemset(void * ptr,int c,size_t n)61351c0b2f7Stbbdev void myMemset(void *ptr, int c, size_t n)
61451c0b2f7Stbbdev {
615734f0bc0SPablo Romero #if  __unix__ &&  __i386__
61651c0b2f7Stbbdev // memset in Fedora 13 not always correctly sets memory to required values.
61751c0b2f7Stbbdev     char *p = (char*)ptr;
61851c0b2f7Stbbdev     for (size_t i=0; i<n; i++)
61951c0b2f7Stbbdev         p[i] = c;
62051c0b2f7Stbbdev #else
62151c0b2f7Stbbdev     memset(ptr, c, n);
62251c0b2f7Stbbdev #endif
62351c0b2f7Stbbdev }
62451c0b2f7Stbbdev 
62551c0b2f7Stbbdev // This test requires more than TOTAL_MB_ALLOC MB of RAM.
62651c0b2f7Stbbdev #if __ANDROID__
62751c0b2f7Stbbdev // Android requires lower limit due to lack of virtual memory.
62851c0b2f7Stbbdev #define TOTAL_MB_ALLOC	200
62951c0b2f7Stbbdev #else
63051c0b2f7Stbbdev #define TOTAL_MB_ALLOC  800
63151c0b2f7Stbbdev #endif
NULLReturn(UINT MinSize,UINT MaxSize,int total_threads)63251c0b2f7Stbbdev void CMemTest::NULLReturn(UINT MinSize, UINT MaxSize, int total_threads)
63351c0b2f7Stbbdev {
63451c0b2f7Stbbdev     const int MB_PER_THREAD = TOTAL_MB_ALLOC / total_threads;
63557f524caSIlya Isaev     // find size to guarantee getting nullptr for 1024 B allocations
63651c0b2f7Stbbdev     const int MAXNUM_1024 = (MB_PER_THREAD + (MB_PER_THREAD>>2)) * 1024;
63751c0b2f7Stbbdev 
63851c0b2f7Stbbdev     std::vector<MemStruct> PointerList;
63951c0b2f7Stbbdev     void *tmp;
640a080baf9SAlex     static std::atomic<int> CountErrors{0};
64151c0b2f7Stbbdev     int CountNULL, num_1024;
64251c0b2f7Stbbdev     if (FullLog) REPORT("\nNULL return & check errno:\n");
64351c0b2f7Stbbdev     UINT Size;
64451c0b2f7Stbbdev     Limit limit_total(TOTAL_MB_ALLOC), no_limit(0);
64551c0b2f7Stbbdev     void **buf_1024 = (void**)Tmalloc(MAXNUM_1024*sizeof(void*));
64651c0b2f7Stbbdev 
64751c0b2f7Stbbdev     REQUIRE(buf_1024);
64851c0b2f7Stbbdev     /* We must have space for pointers when memory limit is hit.
64951c0b2f7Stbbdev        Reserve enough for the worst case, taking into account race for
65051c0b2f7Stbbdev        limited space between threads.
65151c0b2f7Stbbdev     */
65251c0b2f7Stbbdev     PointerList.reserve(TOTAL_MB_ALLOC*MByte/MinSize);
65351c0b2f7Stbbdev 
65451c0b2f7Stbbdev     /* There is a bug in the specific version of GLIBC (2.5-12) shipped
65551c0b2f7Stbbdev        with RHEL5 that leads to erroneous working of the test
65651c0b2f7Stbbdev        on Intel(R) 64 and Itanium(R) architecture when setrlimit-related part is enabled.
65751c0b2f7Stbbdev        Switching to GLIBC 2.5-18 from RHEL5.1 resolved the issue.
65851c0b2f7Stbbdev      */
65951c0b2f7Stbbdev     if (perProcessLimits)
66051c0b2f7Stbbdev         limitBarrier->wait(limit_total);
66151c0b2f7Stbbdev     else
66251c0b2f7Stbbdev         limitMem(MB_PER_THREAD);
66351c0b2f7Stbbdev 
66457f524caSIlya Isaev     /* regression test against the bug in allocator when it dereference nullptr
66551c0b2f7Stbbdev        while lack of memory
66651c0b2f7Stbbdev     */
66751c0b2f7Stbbdev     for (num_1024=0; num_1024<MAXNUM_1024; num_1024++) {
66851c0b2f7Stbbdev         buf_1024[num_1024] = Tcalloc(1024, 1);
66951c0b2f7Stbbdev         if (! buf_1024[num_1024]) {
67057f524caSIlya Isaev             ASSERT_ERRNO(errno == ENOMEM, nullptr);
67151c0b2f7Stbbdev             break;
67251c0b2f7Stbbdev         }
67351c0b2f7Stbbdev     }
67451c0b2f7Stbbdev     for (int i=0; i<num_1024; i++)
67551c0b2f7Stbbdev         Tfree(buf_1024[i]);
67651c0b2f7Stbbdev     Tfree(buf_1024);
67751c0b2f7Stbbdev 
67851c0b2f7Stbbdev     do {
67951c0b2f7Stbbdev         Size=rand()%(MaxSize-MinSize)+MinSize;
68051c0b2f7Stbbdev         tmp=Tmalloc(Size);
68157f524caSIlya Isaev         if (tmp != nullptr)
68251c0b2f7Stbbdev         {
68351c0b2f7Stbbdev             myMemset(tmp, 0, Size);
68451c0b2f7Stbbdev             PointerList.push_back(MemStruct(tmp, Size));
68551c0b2f7Stbbdev         }
68657f524caSIlya Isaev     } while(tmp != nullptr);
68757f524caSIlya Isaev     ASSERT_ERRNO(errno == ENOMEM, nullptr);
68851c0b2f7Stbbdev     if (FullLog) REPORT("\n");
68951c0b2f7Stbbdev 
69051c0b2f7Stbbdev     // preparation complete, now running tests
69151c0b2f7Stbbdev     // malloc
69251c0b2f7Stbbdev     if (FullLog) REPORT("malloc....");
69351c0b2f7Stbbdev     CountNULL = 0;
69451c0b2f7Stbbdev     while (CountNULL==0)
69551c0b2f7Stbbdev         for (int j=0; j<COUNT_TESTS; j++)
69651c0b2f7Stbbdev         {
69751c0b2f7Stbbdev             Size=rand()%(MaxSize-MinSize)+MinSize;
69851c0b2f7Stbbdev             errno = ENOMEM+j+1;
69951c0b2f7Stbbdev             tmp=Tmalloc(Size);
70057f524caSIlya Isaev             if (tmp == nullptr)
70151c0b2f7Stbbdev             {
70251c0b2f7Stbbdev                 CountNULL++;
70351c0b2f7Stbbdev                 if ( CHECK_ERRNO(errno != ENOMEM) ) {
70451c0b2f7Stbbdev                     CountErrors++;
70557f524caSIlya Isaev                     if (ShouldReportError()) REPORT("nullptr returned, error: errno (%d) != ENOMEM\n", errno);
70651c0b2f7Stbbdev                 }
70751c0b2f7Stbbdev             }
70851c0b2f7Stbbdev             else
70951c0b2f7Stbbdev             {
71057f524caSIlya Isaev                 // Technically, if malloc returns a non-null pointer, it is allowed to set errno anyway.
71151c0b2f7Stbbdev                 // However, on most systems it does not set errno.
71251c0b2f7Stbbdev                 bool known_issue = false;
713734f0bc0SPablo Romero #if __unix__ || __ANDROID__
71451c0b2f7Stbbdev                 if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true;
715734f0bc0SPablo Romero #endif /* __unix__ */
71651c0b2f7Stbbdev                 if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue) {
71751c0b2f7Stbbdev                     CountErrors++;
71851c0b2f7Stbbdev                     if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno);
71951c0b2f7Stbbdev                 }
72051c0b2f7Stbbdev                 myMemset(tmp, 0, Size);
72151c0b2f7Stbbdev                 PointerList.push_back(MemStruct(tmp, Size));
72251c0b2f7Stbbdev             }
72351c0b2f7Stbbdev         }
72451c0b2f7Stbbdev     if (FullLog) REPORT("end malloc\n");
72551c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
72651c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
727a080baf9SAlex     if (CountErrors) error_occurred = true;
72851c0b2f7Stbbdev 
72951c0b2f7Stbbdev     //calloc
73051c0b2f7Stbbdev     if (FullLog) REPORT("calloc....");
73151c0b2f7Stbbdev     CountNULL = 0;
73251c0b2f7Stbbdev     while (CountNULL==0)
73351c0b2f7Stbbdev         for (int j=0; j<COUNT_TESTS; j++)
73451c0b2f7Stbbdev         {
73551c0b2f7Stbbdev             Size=rand()%(MaxSize-MinSize)+MinSize;
73651c0b2f7Stbbdev             errno = ENOMEM+j+1;
73751c0b2f7Stbbdev             tmp=Tcalloc(COUNT_ELEM_CALLOC,Size);
73857f524caSIlya Isaev             if (tmp == nullptr)
73951c0b2f7Stbbdev             {
74051c0b2f7Stbbdev                 CountNULL++;
74151c0b2f7Stbbdev                 if ( CHECK_ERRNO(errno != ENOMEM) ){
74251c0b2f7Stbbdev                     CountErrors++;
74357f524caSIlya Isaev                     if (ShouldReportError()) REPORT("nullptr returned, error: errno(%d) != ENOMEM\n", errno);
74451c0b2f7Stbbdev                 }
74551c0b2f7Stbbdev             }
74651c0b2f7Stbbdev             else
74751c0b2f7Stbbdev             {
74857f524caSIlya Isaev                 // Technically, if calloc returns a non-null pointer, it is allowed to set errno anyway.
74951c0b2f7Stbbdev                 // However, on most systems it does not set errno.
75051c0b2f7Stbbdev                 bool known_issue = false;
751734f0bc0SPablo Romero #if __unix__
75251c0b2f7Stbbdev                 if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true;
753734f0bc0SPablo Romero #endif /* __unix__ */
75451c0b2f7Stbbdev                 if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue ) {
75551c0b2f7Stbbdev                     CountErrors++;
75651c0b2f7Stbbdev                     if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno);
75751c0b2f7Stbbdev                 }
75851c0b2f7Stbbdev                 PointerList.push_back(MemStruct(tmp, Size));
75951c0b2f7Stbbdev             }
76051c0b2f7Stbbdev         }
76151c0b2f7Stbbdev     if (FullLog) REPORT("end calloc\n");
76251c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
76351c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
764a080baf9SAlex     if (CountErrors) error_occurred = true;
76551c0b2f7Stbbdev     if (FullLog) REPORT("realloc....");
76651c0b2f7Stbbdev     CountNULL = 0;
76751c0b2f7Stbbdev     if (PointerList.size() > 0)
76851c0b2f7Stbbdev         while (CountNULL==0)
76951c0b2f7Stbbdev             for (size_t i=0; i<(size_t)COUNT_TESTS && i<PointerList.size(); i++)
77051c0b2f7Stbbdev             {
77151c0b2f7Stbbdev                 errno = 0;
77251c0b2f7Stbbdev                 tmp=Trealloc(PointerList[i].Pointer,PointerList[i].Size*2);
77357f524caSIlya Isaev                 if (tmp != nullptr) // same or another place
77451c0b2f7Stbbdev                 {
77551c0b2f7Stbbdev                     bool known_issue = false;
776734f0bc0SPablo Romero #if __unix__
77751c0b2f7Stbbdev                     if( errno==ENOMEM ) known_issue = true;
778734f0bc0SPablo Romero #endif /* __unix__ */
77951c0b2f7Stbbdev                     if (errno != 0 && !known_issue) {
78051c0b2f7Stbbdev                         CountErrors++;
78151c0b2f7Stbbdev                         if (ShouldReportError()) REPORT("valid pointer returned, error: errno not kept\n");
78251c0b2f7Stbbdev                     }
78351c0b2f7Stbbdev                     // newly allocated area have to be zeroed
78451c0b2f7Stbbdev                     myMemset((char*)tmp + PointerList[i].Size, 0, PointerList[i].Size);
78551c0b2f7Stbbdev                     PointerList[i].Pointer = tmp;
78651c0b2f7Stbbdev                     PointerList[i].Size *= 2;
78751c0b2f7Stbbdev                 } else {
78851c0b2f7Stbbdev                     CountNULL++;
78951c0b2f7Stbbdev                     if ( CHECK_ERRNO(errno != ENOMEM) )
79051c0b2f7Stbbdev                     {
79151c0b2f7Stbbdev                         CountErrors++;
79257f524caSIlya Isaev                         if (ShouldReportError()) REPORT("nullptr returned, error: errno(%d) != ENOMEM\n", errno);
79351c0b2f7Stbbdev                     }
79451c0b2f7Stbbdev                     // check data integrity
79551c0b2f7Stbbdev                     if (NonZero(PointerList[i].Pointer, PointerList[i].Size)) {
79651c0b2f7Stbbdev                         CountErrors++;
79757f524caSIlya Isaev                         if (ShouldReportError()) REPORT("nullptr returned, error: data changed\n");
79851c0b2f7Stbbdev                     }
79951c0b2f7Stbbdev                 }
80051c0b2f7Stbbdev             }
80151c0b2f7Stbbdev     if (FullLog) REPORT("realloc end\n");
80251c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
80351c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
804a080baf9SAlex     if (CountErrors) error_occurred = true;
80551c0b2f7Stbbdev     for (UINT i=0; i<PointerList.size(); i++)
80651c0b2f7Stbbdev     {
80751c0b2f7Stbbdev         Tfree(PointerList[i].Pointer);
80851c0b2f7Stbbdev     }
80951c0b2f7Stbbdev 
81051c0b2f7Stbbdev     if (perProcessLimits)
81151c0b2f7Stbbdev         limitBarrier->wait(no_limit);
81251c0b2f7Stbbdev     else
81351c0b2f7Stbbdev         limitMem(0);
81451c0b2f7Stbbdev }
81551c0b2f7Stbbdev #endif /* #if !__APPLE__ */
81651c0b2f7Stbbdev 
UniquePointer()81751c0b2f7Stbbdev void CMemTest::UniquePointer()
81851c0b2f7Stbbdev {
819a080baf9SAlex     static std::atomic<int> CountErrors{0};
82051c0b2f7Stbbdev     int **MasPointer = (int **)Tmalloc(sizeof(int*)*COUNT_ELEM);
82151c0b2f7Stbbdev     size_t *MasCountElem = (size_t*)Tmalloc(sizeof(size_t)*COUNT_ELEM);
82251c0b2f7Stbbdev     if (FullLog) REPORT("\nUnique pointer using 0\n");
82351c0b2f7Stbbdev     REQUIRE((MasCountElem && MasPointer));
82451c0b2f7Stbbdev     //
82551c0b2f7Stbbdev     //-------------------------------------------------------
82651c0b2f7Stbbdev     //malloc
82751c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
82851c0b2f7Stbbdev     {
82951c0b2f7Stbbdev         MasCountElem[i]=rand()%MAX_SIZE;
83051c0b2f7Stbbdev         MasPointer[i]=(int*)Tmalloc(MasCountElem[i]*sizeof(int));
83157f524caSIlya Isaev         if (nullptr == MasPointer[i])
83251c0b2f7Stbbdev             MasCountElem[i]=0;
83351c0b2f7Stbbdev         memset(MasPointer[i], 0, sizeof(int)*MasCountElem[i]);
83451c0b2f7Stbbdev     }
83551c0b2f7Stbbdev     if (FullLog) REPORT("malloc....");
83651c0b2f7Stbbdev     for (UINT i=0; i<COUNT_ELEM-1; i++)
83751c0b2f7Stbbdev     {
83851c0b2f7Stbbdev         if (size_t badOff = NonZero(MasPointer[i], sizeof(int)*MasCountElem[i])) {
83951c0b2f7Stbbdev             CountErrors++;
84051c0b2f7Stbbdev             if (ShouldReportError())
84151c0b2f7Stbbdev                 REPORT("error, detect non-zero at %p\n", (char*)MasPointer[i]+badOff-1);
84251c0b2f7Stbbdev         }
84351c0b2f7Stbbdev         memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]);
84451c0b2f7Stbbdev     }
84551c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
84651c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
847a080baf9SAlex     if (CountErrors) error_occurred = true;
84851c0b2f7Stbbdev     //----------------------------------------------------------
84951c0b2f7Stbbdev     //calloc
85051c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
85151c0b2f7Stbbdev         Tfree(MasPointer[i]);
85251c0b2f7Stbbdev     for (long i=0; i<COUNT_ELEM; i++)
85351c0b2f7Stbbdev     {
85451c0b2f7Stbbdev         MasPointer[i]=(int*)Tcalloc(MasCountElem[i]*sizeof(int),2);
85557f524caSIlya Isaev         if (nullptr == MasPointer[i])
85651c0b2f7Stbbdev             MasCountElem[i]=0;
85751c0b2f7Stbbdev     }
85851c0b2f7Stbbdev     if (FullLog) REPORT("calloc....");
85951c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM-1; i++)
86051c0b2f7Stbbdev     {
86151c0b2f7Stbbdev         if (size_t badOff = NonZero(MasPointer[i], sizeof(int)*MasCountElem[i])) {
86251c0b2f7Stbbdev             CountErrors++;
86351c0b2f7Stbbdev             if (ShouldReportError())
86451c0b2f7Stbbdev                 REPORT("error, detect non-zero at %p\n", (char*)MasPointer[i]+badOff-1);
86551c0b2f7Stbbdev         }
86651c0b2f7Stbbdev         memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]);
86751c0b2f7Stbbdev     }
86851c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
86951c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
870a080baf9SAlex     if (CountErrors) error_occurred = true;
87151c0b2f7Stbbdev     //---------------------------------------------------------
87251c0b2f7Stbbdev     //realloc
87351c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
87451c0b2f7Stbbdev     {
87551c0b2f7Stbbdev         MasCountElem[i]*=2;
87651c0b2f7Stbbdev         *(MasPointer+i)=
87751c0b2f7Stbbdev             (int*)Trealloc(*(MasPointer+i),MasCountElem[i]*sizeof(int));
87857f524caSIlya Isaev         if (nullptr == MasPointer[i])
87951c0b2f7Stbbdev             MasCountElem[i]=0;
88051c0b2f7Stbbdev         memset(MasPointer[i], 0, sizeof(int)*MasCountElem[i]);
88151c0b2f7Stbbdev     }
88251c0b2f7Stbbdev     if (FullLog) REPORT("realloc....");
88351c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM-1; i++)
88451c0b2f7Stbbdev     {
88551c0b2f7Stbbdev         if (NonZero(MasPointer[i], sizeof(int)*MasCountElem[i]))
88651c0b2f7Stbbdev             CountErrors++;
88751c0b2f7Stbbdev         memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]);
88851c0b2f7Stbbdev     }
88951c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
89051c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
891a080baf9SAlex     if (CountErrors) error_occurred = true;
89251c0b2f7Stbbdev     for (int i=0; i<COUNT_ELEM; i++)
89351c0b2f7Stbbdev         Tfree(MasPointer[i]);
89451c0b2f7Stbbdev     Tfree(MasCountElem);
89551c0b2f7Stbbdev     Tfree(MasPointer);
89651c0b2f7Stbbdev }
89751c0b2f7Stbbdev 
ShouldReportError()89851c0b2f7Stbbdev bool CMemTest::ShouldReportError()
89951c0b2f7Stbbdev {
90051c0b2f7Stbbdev     if (FullLog)
90151c0b2f7Stbbdev         return true;
90251c0b2f7Stbbdev     else
90351c0b2f7Stbbdev         if (firstTime) {
90451c0b2f7Stbbdev             firstTime = false;
90551c0b2f7Stbbdev             return true;
90651c0b2f7Stbbdev         } else
90751c0b2f7Stbbdev             return false;
90851c0b2f7Stbbdev }
90951c0b2f7Stbbdev 
Free_NULL()91051c0b2f7Stbbdev void CMemTest::Free_NULL()
91151c0b2f7Stbbdev {
912a080baf9SAlex     static std::atomic<int> CountErrors{0};
91357f524caSIlya Isaev     if (FullLog) REPORT("\ncall free with parameter nullptr....");
91451c0b2f7Stbbdev     errno = 0;
91551c0b2f7Stbbdev     for (int i=0; i<COUNTEXPERIMENT; i++)
91651c0b2f7Stbbdev     {
91757f524caSIlya Isaev         Tfree(nullptr);
91851c0b2f7Stbbdev         if (CHECK_ERRNO(errno))
91951c0b2f7Stbbdev         {
92051c0b2f7Stbbdev             CountErrors++;
92157f524caSIlya Isaev             if (ShouldReportError()) REPORT("error is found by a call free with parameter nullptr\n");
92251c0b2f7Stbbdev         }
92351c0b2f7Stbbdev     }
92451c0b2f7Stbbdev     if (CountErrors) REPORT("%s\n",strError);
92551c0b2f7Stbbdev     else if (FullLog) REPORT("%s\n",strOk);
926a080baf9SAlex     if (CountErrors) error_occurred = true;
92751c0b2f7Stbbdev }
92851c0b2f7Stbbdev 
TestAlignedParameters()92951c0b2f7Stbbdev void CMemTest::TestAlignedParameters()
93051c0b2f7Stbbdev {
93151c0b2f7Stbbdev     void *memptr;
93251c0b2f7Stbbdev     int ret;
93351c0b2f7Stbbdev 
93451c0b2f7Stbbdev     if (Rposix_memalign) {
93551c0b2f7Stbbdev         // alignment isn't power of 2
93651c0b2f7Stbbdev         for (int bad_align=3; bad_align<16; bad_align++)
93751c0b2f7Stbbdev             if (bad_align&(bad_align-1)) {
93857f524caSIlya Isaev                 ret = Tposix_memalign(nullptr, bad_align, 100);
93951c0b2f7Stbbdev                 REQUIRE(EINVAL==ret);
94051c0b2f7Stbbdev             }
94151c0b2f7Stbbdev 
94251c0b2f7Stbbdev         memptr = &ret;
94351c0b2f7Stbbdev         ret = Tposix_memalign(&memptr, 5*sizeof(void*), 100);
94451c0b2f7Stbbdev         REQUIRE_MESSAGE(memptr == &ret,
94551c0b2f7Stbbdev                "memptr should not be changed after unsuccessful call");
94651c0b2f7Stbbdev         REQUIRE(EINVAL==ret);
94751c0b2f7Stbbdev 
94851c0b2f7Stbbdev         // alignment is power of 2, but not a multiple of sizeof(void *),
94951c0b2f7Stbbdev         // we expect that sizeof(void*) > 2
95057f524caSIlya Isaev         ret = Tposix_memalign(nullptr, 2, 100);
95151c0b2f7Stbbdev         REQUIRE(EINVAL==ret);
95251c0b2f7Stbbdev     }
95351c0b2f7Stbbdev     if (Raligned_malloc) {
95451c0b2f7Stbbdev         // alignment isn't power of 2
95551c0b2f7Stbbdev         for (int bad_align=3; bad_align<16; bad_align++)
95651c0b2f7Stbbdev             if (bad_align&(bad_align-1)) {
95751c0b2f7Stbbdev                 memptr = Taligned_malloc(100, bad_align);
95851c0b2f7Stbbdev                 REQUIRE(memptr == nullptr);
95957f524caSIlya Isaev                 ASSERT_ERRNO(EINVAL==errno, nullptr);
96051c0b2f7Stbbdev             }
96151c0b2f7Stbbdev 
96251c0b2f7Stbbdev         // size is zero
96351c0b2f7Stbbdev         memptr = Taligned_malloc(0, 16);
96457f524caSIlya Isaev         REQUIRE_MESSAGE(memptr == nullptr, "size is zero, so must return nullptr");
96557f524caSIlya Isaev         ASSERT_ERRNO(EINVAL==errno, nullptr);
96651c0b2f7Stbbdev     }
96751c0b2f7Stbbdev     if (Taligned_free) {
96857f524caSIlya Isaev         // nullptr pointer is OK to free
96951c0b2f7Stbbdev         errno = 0;
97057f524caSIlya Isaev         Taligned_free(nullptr);
97151c0b2f7Stbbdev         /* As there is no return value for free, strictly speaking we can't
97251c0b2f7Stbbdev            check errno here. But checked implementations obey the assertion.
97351c0b2f7Stbbdev         */
97457f524caSIlya Isaev         ASSERT_ERRNO(0==errno, nullptr);
97551c0b2f7Stbbdev     }
97651c0b2f7Stbbdev     if (Raligned_realloc) {
97751c0b2f7Stbbdev         for (int i=1; i<20; i++) {
97851c0b2f7Stbbdev             // checks that calls work correctly in presence of non-zero errno
97951c0b2f7Stbbdev             errno = i;
98051c0b2f7Stbbdev             void *ptr = Taligned_malloc(i*10, 128);
98151c0b2f7Stbbdev             REQUIRE(ptr != nullptr);
98257f524caSIlya Isaev             ASSERT_ERRNO(0!=errno, nullptr);
98357f524caSIlya Isaev             // if size is zero and pointer is not nullptr, works like free
98451c0b2f7Stbbdev             memptr = Taligned_realloc(ptr, 0, 64);
98551c0b2f7Stbbdev             REQUIRE(memptr == nullptr);
98657f524caSIlya Isaev             ASSERT_ERRNO(0!=errno, nullptr);
98751c0b2f7Stbbdev         }
98851c0b2f7Stbbdev         // alignment isn't power of 2
98951c0b2f7Stbbdev         for (int bad_align=3; bad_align<16; bad_align++)
99051c0b2f7Stbbdev             if (bad_align&(bad_align-1)) {
99151c0b2f7Stbbdev                 void *ptr = &bad_align;
99251c0b2f7Stbbdev                 memptr = Taligned_realloc(&ptr, 100, bad_align);
99351c0b2f7Stbbdev                 REQUIRE(memptr == nullptr);
99451c0b2f7Stbbdev                 REQUIRE(&bad_align==ptr);
99557f524caSIlya Isaev                 ASSERT_ERRNO(EINVAL==errno, nullptr);
99651c0b2f7Stbbdev             }
99751c0b2f7Stbbdev     }
99851c0b2f7Stbbdev }
99951c0b2f7Stbbdev 
RunAllTests(int total_threads)100051c0b2f7Stbbdev void CMemTest::RunAllTests(int total_threads)
100151c0b2f7Stbbdev {
100251c0b2f7Stbbdev     Zerofilling();
100351c0b2f7Stbbdev     Free_NULL();
100451c0b2f7Stbbdev     InvariantDataRealloc(/*aligned=*/false, 8*MByte, /*checkData=*/true);
100551c0b2f7Stbbdev     if (Raligned_realloc)
100651c0b2f7Stbbdev         InvariantDataRealloc(/*aligned=*/true, 8*MByte, /*checkData=*/true);
100751c0b2f7Stbbdev     TestAlignedParameters();
100851c0b2f7Stbbdev     UniquePointer();
100951c0b2f7Stbbdev     AddrArifm();
1010a080baf9SAlex #if __APPLE__ || __TBB_USE_THREAD_SANITIZER
101151c0b2f7Stbbdev     REPORT("Known issue: some tests are skipped on macOS\n");
101251c0b2f7Stbbdev #else
1013a080baf9SAlex     // TODO: enable
101451c0b2f7Stbbdev     NULLReturn(1*MByte,100*MByte,total_threads);
101551c0b2f7Stbbdev #endif
101651c0b2f7Stbbdev     if (FullLog) REPORT("Tests for %d threads ended\n", total_threads);
101751c0b2f7Stbbdev }
101851c0b2f7Stbbdev 
101951c0b2f7Stbbdev // TODO: fix the tests to support UWP mode
102051c0b2f7Stbbdev #if !__TBB_WIN8UI_SUPPORT
102151c0b2f7Stbbdev 
102251c0b2f7Stbbdev TEST_CASE("MAIN TEST") {
102351c0b2f7Stbbdev     Rmalloc=scalable_malloc;
102451c0b2f7Stbbdev     Rrealloc=scalable_realloc;
102551c0b2f7Stbbdev     Rcalloc=scalable_calloc;
102651c0b2f7Stbbdev     Tfree=scalable_free;
102751c0b2f7Stbbdev     Rposix_memalign=scalable_posix_memalign;
102851c0b2f7Stbbdev     Raligned_malloc=scalable_aligned_malloc;
102951c0b2f7Stbbdev     Raligned_realloc=scalable_aligned_realloc;
103051c0b2f7Stbbdev     Taligned_free=scalable_aligned_free;
103151c0b2f7Stbbdev 
103251c0b2f7Stbbdev     // Check if we were called to test standard behavior
103351c0b2f7Stbbdev     // TODO: enable this mode
103451c0b2f7Stbbdev     // setSystemAllocs();
1035734f0bc0SPablo Romero #if __unix__
103651c0b2f7Stbbdev     /* According to man pthreads
103751c0b2f7Stbbdev        "NPTL threads do not share resource limits (fixed in kernel 2.6.10)".
103851c0b2f7Stbbdev        Use per-threads limits for affected systems.
103951c0b2f7Stbbdev      */
104051c0b2f7Stbbdev     if ( utils::LinuxKernelVersion() < 2*1000000 + 6*1000 + 10)
104151c0b2f7Stbbdev         perProcessLimits = false;
104251c0b2f7Stbbdev #endif
104351c0b2f7Stbbdev     //-------------------------------------
1044a080baf9SAlex #if __APPLE__ || __TBB_USE_SANITIZERS
104551c0b2f7Stbbdev     /* Skip due to lack of memory limit enforcing under macOS. */
1046c0b91bdbSAnton Potapov     //Skip this test under ASAN , as OOM condition breaks the ASAN as well
104751c0b2f7Stbbdev #else
104851c0b2f7Stbbdev     limitMem(200);
104951c0b2f7Stbbdev     ReallocParam();
105051c0b2f7Stbbdev     limitMem(0);
105151c0b2f7Stbbdev #endif
105251c0b2f7Stbbdev 
105351c0b2f7Stbbdev //for linux and dynamic runtime errno is used to check allocator functions
105451c0b2f7Stbbdev //check if library compiled with /MD(d) and we can use errno
105551c0b2f7Stbbdev #if _MSC_VER
105651c0b2f7Stbbdev #if defined(_MT) && defined(_DLL) //check errno if test itself compiled with /MD(d) only
105757f524caSIlya Isaev     char*  version_info_block = nullptr;
105851c0b2f7Stbbdev     int version_info_block_size;
105957f524caSIlya Isaev     LPVOID comments_block = nullptr;
106051c0b2f7Stbbdev     UINT comments_block_size;
106151c0b2f7Stbbdev #ifdef _DEBUG
106251c0b2f7Stbbdev #define __TBBMALLOCDLL "tbbmalloc_debug.dll"
106351c0b2f7Stbbdev #else  //_DEBUG
106451c0b2f7Stbbdev #define __TBBMALLOCDLL "tbbmalloc.dll"
106551c0b2f7Stbbdev #endif //_DEBUG
106651c0b2f7Stbbdev     version_info_block_size = GetFileVersionInfoSize( __TBBMALLOCDLL, (LPDWORD)&version_info_block_size );
106751c0b2f7Stbbdev     if( version_info_block_size
106857f524caSIlya Isaev         && ((version_info_block = (char*)malloc(version_info_block_size)) != nullptr)
106951c0b2f7Stbbdev         && GetFileVersionInfo(  __TBBMALLOCDLL, NULL, version_info_block_size, version_info_block )
107051c0b2f7Stbbdev         && VerQueryValue( version_info_block, "\\StringFileInfo\\000004b0\\Comments", &comments_block, &comments_block_size )
107151c0b2f7Stbbdev         && strstr( (char*)comments_block, "/MD" )
107251c0b2f7Stbbdev         ){
107351c0b2f7Stbbdev             __tbb_test_errno = true;
107451c0b2f7Stbbdev      }
107551c0b2f7Stbbdev      if( version_info_block ) free( version_info_block );
107651c0b2f7Stbbdev #endif // defined(_MT) && defined(_DLL)
107751c0b2f7Stbbdev #else  // _MSC_VER
107851c0b2f7Stbbdev     __tbb_test_errno = true;
107951c0b2f7Stbbdev #endif // _MSC_VER
108051c0b2f7Stbbdev 
108151c0b2f7Stbbdev     CheckArgumentsOverflow();
108251c0b2f7Stbbdev     CheckReallocLeak();
108351c0b2f7Stbbdev     for( int p=MaxThread; p>=MinThread; --p ) {
108451c0b2f7Stbbdev         for (int limit=0; limit<2; limit++) {
108551c0b2f7Stbbdev             int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT, 16*1024*limit);
108651c0b2f7Stbbdev             REQUIRE(ret==TBBMALLOC_OK);
108751c0b2f7Stbbdev             utils::SpinBarrier *barrier = new utils::SpinBarrier(p);
108851c0b2f7Stbbdev             utils::NativeParallelFor( p, RoundRobin(p, barrier, Verbose) );
108951c0b2f7Stbbdev             delete barrier;
109051c0b2f7Stbbdev         }
109151c0b2f7Stbbdev     }
109251c0b2f7Stbbdev     int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT, 0);
109351c0b2f7Stbbdev     REQUIRE(ret==TBBMALLOC_OK);
109451c0b2f7Stbbdev     REQUIRE(!error_occurred);
109551c0b2f7Stbbdev }
109651c0b2f7Stbbdev 
109751c0b2f7Stbbdev #endif /* __TBB_WIN8UI_SUPPORT	 */
1098*ab7f370cSPavel Kumbrasev #endif /* Enable test */
1099