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