1 /*
2 Copyright (c) 2005-2020 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 bool __tbb_test_errno = false;
18
19 #define __STDC_LIMIT_MACROS 1 // to get SIZE_MAX from stdint.h
20
21 #include "tbb/tbb_config.h"
22
23 #if __TBB_WIN8UI_SUPPORT
24 // testing allocator itself not interfaces
25 // so we can use desktop functions
26 #define _CRT_USE_WINAPI_FAMILY_DESKTOP_APP !_M_ARM
27 #define HARNESS_NO_PARSE_COMMAND_LINE 1
28 #include "harness.h"
29 // FIXME: fix the test to support New Windows *8 Store Apps mode.
TestMain()30 int TestMain() {
31 return Harness::Skipped;
32 }
33 #else /* __TBB_WIN8UI_SUPPORT */
34
35 #include "harness_defs.h"
36 #include "harness_report.h"
37
38 #if _WIN32 || _WIN64
39 /* _WIN32_WINNT should be defined at the very beginning,
40 because other headers might include <windows.h>
41 */
42 #undef _WIN32_WINNT
43 #define _WIN32_WINNT 0x0501
44 #include "tbb/machine/windows_api.h"
45 #include <stdio.h>
46
47 #if _MSC_VER && defined(_MT) && defined(_DLL)
48 #pragma comment(lib, "version.lib") // to use GetFileVersionInfo*
49 #endif
50
limitMem(size_t limit)51 void limitMem( size_t limit )
52 {
53 static HANDLE hJob = NULL;
54 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;
55
56 jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
57 jobInfo.ProcessMemoryLimit = limit? limit*MByte : 2*MByte*1024;
58 if (NULL == hJob) {
59 if (NULL == (hJob = CreateJobObject(NULL, NULL))) {
60 REPORT("Can't assign create job object: %ld\n", GetLastError());
61 exit(1);
62 }
63 if (0 == AssignProcessToJobObject(hJob, GetCurrentProcess())) {
64 REPORT("Can't assign process to job object: %ld\n", GetLastError());
65 exit(1);
66 }
67 }
68 if (0 == SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
69 &jobInfo, sizeof(jobInfo))) {
70 REPORT("Can't set limits: %ld\n", GetLastError());
71 exit(1);
72 }
73 }
74 // Do not test errno with static VC runtime
75 #else // _WIN32 || _WIN64
76 #include <sys/resource.h>
77 #include <stdlib.h>
78 #include <stdio.h>
79 #include <errno.h>
80 #include <sys/types.h> // uint64_t on FreeBSD, needed for rlim_t
81 #include <stdint.h> // SIZE_MAX
82
limitMem(size_t limit)83 void limitMem( size_t limit )
84 {
85 rlimit rlim;
86 int ret = getrlimit(RLIMIT_AS,&rlim);
87 if (0 != ret) {
88 REPORT("getrlimit() returned an error: errno %d\n", errno);
89 exit(1);
90 }
91 if (rlim.rlim_max==(rlim_t)RLIM_INFINITY)
92 rlim.rlim_cur = (limit > 0) ? limit*MByte : rlim.rlim_max;
93 else rlim.rlim_cur = (limit > 0 && limit<rlim.rlim_max) ? limit*MByte : rlim.rlim_max;
94 ret = setrlimit(RLIMIT_AS,&rlim);
95 if (0 != ret) {
96 REPORT("Can't set limits: errno %d\n", errno);
97 exit(1);
98 }
99 }
100 #endif // _WIN32 || _WIN64
101
102 #define ASSERT_ERRNO(cond, msg) ASSERT( !__tbb_test_errno || (cond), msg )
103 #define CHECK_ERRNO(cond) (__tbb_test_errno && (cond))
104
105 #include <time.h>
106 #include <errno.h>
107 #include <limits.h> // for CHAR_BIT
108 #define __TBB_NO_IMPLICIT_LINKAGE 1
109 #include "tbb/scalable_allocator.h"
110
111 #define HARNESS_CUSTOM_MAIN 1
112 #define HARNESS_TBBMALLOC_THREAD_SHUTDOWN 1
113 #include "harness.h"
114 #include "harness_barrier.h"
115 #if !__TBB_SOURCE_DIRECTLY_INCLUDED
116 #include "harness_tbb_independence.h"
117 #endif
118 #if __linux__
119 #include <stdint.h> // uintptr_t
120 #endif
121 #if _WIN32 || _WIN64
122 #include <malloc.h> // _aligned_(malloc|free|realloc)
123 #if __MINGW64__
124 // Workaround a bug in MinGW64 headers with _aligned_(malloc|free) not declared by default
125 extern "C" void __cdecl _aligned_free(void *);
126 extern "C" void *__cdecl _aligned_malloc(size_t,size_t);
127 #endif
128 #endif
129
130 #include <vector>
131
132 const int COUNT_ELEM = 25000;
133 const size_t MAX_SIZE = 1000;
134 const int COUNTEXPERIMENT = 10000;
135
136 const char strError[]="failed";
137 const char strOk[]="done";
138
139 typedef unsigned int UINT;
140 typedef unsigned char UCHAR;
141 typedef unsigned long DWORD;
142 typedef unsigned char BYTE;
143
144
145 typedef void* TestMalloc(size_t size);
146 typedef void* TestCalloc(size_t num, size_t size);
147 typedef void* TestRealloc(void* memblock, size_t size);
148 typedef void TestFree(void* memblock);
149 typedef int TestPosixMemalign(void **memptr, size_t alignment, size_t size);
150 typedef void* TestAlignedMalloc(size_t size, size_t alignment);
151 typedef void* TestAlignedRealloc(void* memblock, size_t size, size_t alignment);
152 typedef void TestAlignedFree(void* memblock);
153
154 // pointers to tested functions
155 TestMalloc* Rmalloc;
156 TestCalloc* Rcalloc;
157 TestRealloc* Rrealloc;
158 TestFree* Tfree;
159 TestPosixMemalign* Rposix_memalign;
160 TestAlignedMalloc* Raligned_malloc;
161 TestAlignedRealloc* Raligned_realloc;
162 TestAlignedFree* Taligned_free;
163
164 // call functions via pointer and check result's alignment
165 void* Tmalloc(size_t size);
166 void* Tcalloc(size_t num, size_t size);
167 void* Trealloc(void* memblock, size_t size);
168 int Tposix_memalign(void **memptr, size_t alignment, size_t size);
169 void* Taligned_malloc(size_t size, size_t alignment);
170 void* Taligned_realloc(void* memblock, size_t size, size_t alignment);
171
172
173 bool error_occurred = false;
174
175 #if __APPLE__
176 // Tests that use the variables are skipped on macOS*
177 #else
178 const size_t COUNT_ELEM_CALLOC = 2;
179 const int COUNT_TESTS = 1000;
180 static bool perProcessLimits = true;
181 #endif
182
183 const size_t POWERS_OF_2 = 20;
184
185 struct MemStruct
186 {
187 void* Pointer;
188 UINT Size;
189
MemStructMemStruct190 MemStruct() : Pointer(NULL), Size(0) {}
MemStructMemStruct191 MemStruct(void* ptr, UINT sz) : Pointer(ptr), Size(sz) {}
192 };
193
194 class CMemTest: NoAssign
195 {
196 UINT CountErrors;
197 bool FullLog;
198 Harness::SpinBarrier *limitBarrier;
199 static bool firstTime;
200
201 public:
CMemTest(Harness::SpinBarrier * barrier,bool isVerbose=false)202 CMemTest(Harness::SpinBarrier *barrier, bool isVerbose=false) :
203 CountErrors(0), limitBarrier(barrier)
204 {
205 srand((UINT)time(NULL));
206 FullLog=isVerbose;
207 }
208 void NULLReturn(UINT MinSize, UINT MaxSize, int total_threads); // NULL pointer + check errno
209 void UniquePointer(); // unique pointer - check with padding
210 void AddrArifm(); // unique pointer - check with pointer arithmetic
211 bool ShouldReportError();
212 void Free_NULL(); //
213 void Zerofilling(); // check if arrays are zero-filled
214 void TestAlignedParameters();
215 void RunAllTests(int total_threads);
~CMemTest()216 ~CMemTest() {}
217 };
218
219 class Limit {
220 size_t limit;
221 public:
Limit(size_t a_limit)222 Limit(size_t a_limit) : limit(a_limit) {}
operator ()() const223 void operator() () const {
224 limitMem(limit);
225 }
226 };
227
228 int argC;
229 char** argV;
230
231 struct RoundRobin: NoAssign {
232 const long number_of_threads;
233 mutable CMemTest test;
234
RoundRobinRoundRobin235 RoundRobin( long p, Harness::SpinBarrier *limitBarrier, bool verbose ) :
236 number_of_threads(p), test(limitBarrier, verbose) {}
operator ()RoundRobin237 void operator()( int /*id*/ ) const
238 {
239 test.RunAllTests(number_of_threads);
240 }
241 };
242
243 bool CMemTest::firstTime = true;
244
choose_random_alignment()245 inline size_t choose_random_alignment() {
246 return sizeof(void*)<<(rand() % POWERS_OF_2);
247 }
248
setSystemAllocs()249 static void setSystemAllocs()
250 {
251 Rmalloc=malloc;
252 Rrealloc=realloc;
253 Rcalloc=calloc;
254 Tfree=free;
255 #if _WIN32 || _WIN64
256 Raligned_malloc=_aligned_malloc;
257 Raligned_realloc=_aligned_realloc;
258 Taligned_free=_aligned_free;
259 Rposix_memalign=0;
260 #elif __APPLE__ || __sun || __ANDROID__
261 // macOS, Solaris*, and Android* don't have posix_memalign
262 Raligned_malloc=0;
263 Raligned_realloc=0;
264 Taligned_free=0;
265 Rposix_memalign=0;
266 #else
267 Raligned_malloc=0;
268 Raligned_realloc=0;
269 Taligned_free=0;
270 Rposix_memalign=posix_memalign;
271 #endif
272 }
273
274 // check that realloc works as free and as malloc
ReallocParam()275 void ReallocParam()
276 {
277 const int ITERS = 1000;
278 int i;
279 void *bufs[ITERS];
280
281 bufs[0] = Trealloc(NULL, 30*MByte);
282 ASSERT(bufs[0], "Can't get memory to start the test.");
283
284 for (i=1; i<ITERS; i++)
285 {
286 bufs[i] = Trealloc(NULL, 30*MByte);
287 if (NULL == bufs[i])
288 break;
289 }
290 ASSERT(i<ITERS, "Limits should be decreased for the test to work.");
291
292 Trealloc(bufs[0], 0);
293 /* There is a race for the free space between different threads at
294 this point. So, have to run the test sequentially.
295 */
296 bufs[0] = Trealloc(NULL, 30*MByte);
297 ASSERT(bufs[0], NULL);
298
299 for (int j=0; j<i; j++)
300 Trealloc(bufs[j], 0);
301 }
302
CheckArgumentsOverflow()303 void CheckArgumentsOverflow()
304 {
305 void *p;
306 const size_t params[] = {SIZE_MAX, SIZE_MAX-16};
307
308 for (unsigned i=0; i<Harness::array_length(params); i++) {
309 p = Tmalloc(params[i]);
310 ASSERT(!p, NULL);
311 ASSERT_ERRNO(errno==ENOMEM, NULL);
312 p = Trealloc(NULL, params[i]);
313 ASSERT(!p, NULL);
314 ASSERT_ERRNO(errno==ENOMEM, NULL);
315 p = Tcalloc(1, params[i]);
316 ASSERT(!p, NULL);
317 ASSERT_ERRNO(errno==ENOMEM, NULL);
318 p = Tcalloc(params[i], 1);
319 ASSERT(!p, NULL);
320 ASSERT_ERRNO(errno==ENOMEM, NULL);
321 }
322 const size_t max_alignment = size_t(1) << (sizeof(size_t)*CHAR_BIT - 1);
323 if (Rposix_memalign) {
324 int ret = Rposix_memalign(&p, max_alignment, ~max_alignment);
325 ASSERT(ret == ENOMEM, NULL);
326 for (unsigned i=0; i<Harness::array_length(params); i++) {
327 ret = Rposix_memalign(&p, max_alignment, params[i]);
328 ASSERT(ret == ENOMEM, NULL);
329 ret = Rposix_memalign(&p, sizeof(void*), params[i]);
330 ASSERT(ret == ENOMEM, NULL);
331 }
332 }
333 if (Raligned_malloc) {
334 p = Raligned_malloc(~max_alignment, max_alignment);
335 ASSERT(!p, NULL);
336 for (unsigned i=0; i<Harness::array_length(params); i++) {
337 p = Raligned_malloc(params[i], max_alignment);
338 ASSERT(!p, NULL);
339 ASSERT_ERRNO(errno==ENOMEM, NULL);
340 p = Raligned_malloc(params[i], sizeof(void*));
341 ASSERT(!p, NULL);
342 ASSERT_ERRNO(errno==ENOMEM, NULL);
343 }
344 }
345
346 p = Tcalloc(SIZE_MAX/2-16, SIZE_MAX/2-16);
347 ASSERT(!p, NULL);
348 ASSERT_ERRNO(errno==ENOMEM, NULL);
349 p = Tcalloc(SIZE_MAX/2, SIZE_MAX/2);
350 ASSERT(!p, NULL);
351 ASSERT_ERRNO(errno==ENOMEM, NULL);
352 }
353
InvariantDataRealloc(bool aligned,size_t maxAllocSize,bool checkData)354 void InvariantDataRealloc(bool aligned, size_t maxAllocSize, bool checkData)
355 {
356 Harness::FastRandom fastRandom(1);
357 size_t size = 0, start = 0;
358 char *ptr = NULL,
359 // master to create copies and compare ralloc result against it
360 *master = (char*)Tmalloc(2*maxAllocSize);
361
362 ASSERT(master, NULL);
363 ASSERT(!(2*maxAllocSize%sizeof(unsigned short)),
364 "The loop below expects that 2*maxAllocSize contains sizeof(unsigned short)");
365 for (size_t k = 0; k<2*maxAllocSize; k+=sizeof(unsigned short))
366 *(unsigned short*)(master+k) = fastRandom.get();
367
368 for (int i=0; i<100; i++) {
369 // don't want sizeNew==0 here
370 const size_t sizeNew = fastRandom.get() % (maxAllocSize-1) + 1;
371 char *ptrNew = aligned?
372 (char*)Taligned_realloc(ptr, sizeNew, choose_random_alignment())
373 : (char*)Trealloc(ptr, sizeNew);
374 ASSERT(ptrNew, NULL);
375 // check that old data not changed
376 if (checkData)
377 ASSERT(!memcmp(ptrNew, master+start, min(size, sizeNew)), "broken data");
378
379 // prepare fresh data, copying them from random position in master
380 size = sizeNew;
381 ptr = ptrNew;
382 if (checkData) {
383 start = fastRandom.get() % maxAllocSize;
384 memcpy(ptr, master+start, size);
385 }
386 }
387 if (aligned)
388 Taligned_realloc(ptr, 0, choose_random_alignment());
389 else
390 Trealloc(ptr, 0);
391 Tfree(master);
392 }
393
394 #include "harness_memory.h"
395
CheckReallocLeak()396 void CheckReallocLeak()
397 {
398 int i;
399 const int ITER_TO_STABILITY = 10;
400 // do bootstrap
401 for (int k=0; k<3; k++)
402 InvariantDataRealloc(/*aligned=*/false, 128*MByte, /*checkData=*/false);
403 size_t prev = GetMemoryUsage(peakUsage);
404 // expect realloc to not increase peak memory consumption after ITER_TO_STABILITY-1 iterations
405 for (i=0; i<ITER_TO_STABILITY; i++) {
406 for (int k=0; k<3; k++)
407 InvariantDataRealloc(/*aligned=*/false, 128*MByte, /*checkData=*/false);
408 size_t curr = GetMemoryUsage(peakUsage);
409 if (prev == curr)
410 break;
411 prev = curr;
412 }
413 ASSERT(i < ITER_TO_STABILITY, "Can't stabilize memory consumption.");
414 }
415
416 HARNESS_EXPORT
main(int argc,char * argv[])417 int main(int argc, char* argv[]) {
418 argC=argc;
419 argV=argv;
420 MaxThread = MinThread = 1;
421 Rmalloc=scalable_malloc;
422 Rrealloc=scalable_realloc;
423 Rcalloc=scalable_calloc;
424 Tfree=scalable_free;
425 Rposix_memalign=scalable_posix_memalign;
426 Raligned_malloc=scalable_aligned_malloc;
427 Raligned_realloc=scalable_aligned_realloc;
428 Taligned_free=scalable_aligned_free;
429
430 // check if we were called to test standard behavior
431 for (int i=1; i< argc; i++) {
432 if (strcmp((char*)*(argv+i),"-s")==0)
433 {
434 #if __INTEL_COMPILER == 1400 && __linux__
435 // Workaround for Intel(R) C++ Compiler XE, version 14.0.0.080:
436 // unable to call setSystemAllocs() in such configuration.
437 REPORT("Known issue: Standard allocator testing is not supported.\n");
438 REPORT( "skip\n" );
439 return 0;
440 #else
441 setSystemAllocs();
442 argC--;
443 break;
444 #endif
445 }
446 }
447
448 ParseCommandLine( argC, argV );
449 #if __linux__
450 /* According to man pthreads
451 "NPTL threads do not share resource limits (fixed in kernel 2.6.10)".
452 Use per-threads limits for affected systems.
453 */
454 if ( LinuxKernelVersion() < 2*1000000 + 6*1000 + 10)
455 perProcessLimits = false;
456 #endif
457 //-------------------------------------
458 #if __APPLE__
459 /* Skip due to lack of memory limit enforcing under macOS. */
460 #else
461 limitMem(200);
462 ReallocParam();
463 limitMem(0);
464 #endif
465
466 //for linux and dynamic runtime errno is used to check allocator functions
467 //check if library compiled with /MD(d) and we can use errno
468 #if _MSC_VER
469 #if defined(_MT) && defined(_DLL) //check errno if test itself compiled with /MD(d) only
470 char* version_info_block = NULL;
471 int version_info_block_size;
472 LPVOID comments_block = NULL;
473 UINT comments_block_size;
474 #ifdef _DEBUG
475 #define __TBBMALLOCDLL "tbbmalloc_debug.dll"
476 #else //_DEBUG
477 #define __TBBMALLOCDLL "tbbmalloc.dll"
478 #endif //_DEBUG
479 version_info_block_size = GetFileVersionInfoSize( __TBBMALLOCDLL, (LPDWORD)&version_info_block_size );
480 if( version_info_block_size
481 && ((version_info_block = (char*)malloc(version_info_block_size)) != NULL)
482 && GetFileVersionInfo( __TBBMALLOCDLL, NULL, version_info_block_size, version_info_block )
483 && VerQueryValue( version_info_block, "\\StringFileInfo\\000004b0\\Comments", &comments_block, &comments_block_size )
484 && strstr( (char*)comments_block, "/MD" )
485 ){
486 __tbb_test_errno = true;
487 }
488 if( version_info_block ) free( version_info_block );
489 #endif // defined(_MT) && defined(_DLL)
490 #else // _MSC_VER
491 __tbb_test_errno = true;
492 #endif // _MSC_VER
493
494 CheckArgumentsOverflow();
495 CheckReallocLeak();
496 for( int p=MaxThread; p>=MinThread; --p ) {
497 REMARK("testing with %d threads\n", p );
498 for (int limit=0; limit<2; limit++) {
499 int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT,
500 16*1024*limit);
501 ASSERT(ret==TBBMALLOC_OK, NULL);
502 Harness::SpinBarrier *barrier = new Harness::SpinBarrier(p);
503 NativeParallelFor( p, RoundRobin(p, barrier, Verbose) );
504 delete barrier;
505 }
506 }
507 int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT, 0);
508 ASSERT(ret==TBBMALLOC_OK, NULL);
509 if( !error_occurred )
510 REPORT("done\n");
511 return 0;
512 }
513
514 // if non-zero byte found, returns bad value address plus 1
NonZero(void * ptr,size_t size)515 size_t NonZero(void *ptr, size_t size)
516 {
517 size_t words = size / sizeof(intptr_t);
518 size_t tailSz = size % sizeof(intptr_t);
519 intptr_t *buf =(intptr_t*)ptr;
520 char *bufTail =(char*)(buf+words);
521
522 for (size_t i=0; i<words; i++)
523 if (buf[i]) {
524 for (unsigned b=0; b<sizeof(intptr_t); b++)
525 if (((char*)(buf+i))[b])
526 return sizeof(intptr_t)*i + b + 1;
527 }
528 for (size_t i=0; i<tailSz; i++)
529 if (bufTail[i]) {
530 return words*sizeof(intptr_t)+i+1;
531 }
532 return 0;
533 }
534
535 struct TestStruct
536 {
537 DWORD field1:2;
538 DWORD field2:6;
539 double field3;
540 UCHAR field4[100];
541 TestStruct* field5;
542 std::vector<int> field7;
543 double field8;
544 };
545
Tmalloc(size_t size)546 void* Tmalloc(size_t size)
547 {
548 // For compatibility, on 64-bit systems malloc should align to 16 bytes
549 size_t alignment = (sizeof(intptr_t)>4 && size>8) ? 16 : 8;
550 void *ret = Rmalloc(size);
551 if (0 != ret)
552 ASSERT(0==((uintptr_t)ret & (alignment-1)),
553 "allocation result should be properly aligned");
554 return ret;
555 }
Tcalloc(size_t num,size_t size)556 void* Tcalloc(size_t num, size_t size)
557 {
558 // For compatibility, on 64-bit systems calloc should align to 16 bytes
559 size_t alignment = (sizeof(intptr_t)>4 && num && size>8) ? 16 : 8;
560 void *ret = Rcalloc(num, size);
561 if (0 != ret)
562 ASSERT(0==((uintptr_t)ret & (alignment-1)),
563 "allocation result should be properly aligned");
564 return ret;
565 }
Trealloc(void * memblock,size_t size)566 void* Trealloc(void* memblock, size_t size)
567 {
568 // For compatibility, on 64-bit systems realloc should align to 16 bytes
569 size_t alignment = (sizeof(intptr_t)>4 && size>8) ? 16 : 8;
570 void *ret = Rrealloc(memblock, size);
571 if (0 != ret)
572 ASSERT(0==((uintptr_t)ret & (alignment-1)),
573 "allocation result should be properly aligned");
574 return ret;
575 }
Tposix_memalign(void ** memptr,size_t alignment,size_t size)576 int Tposix_memalign(void **memptr, size_t alignment, size_t size)
577 {
578 int ret = Rposix_memalign(memptr, alignment, size);
579 if (0 == ret)
580 ASSERT(0==((uintptr_t)*memptr & (alignment-1)),
581 "allocation result should be aligned");
582 return ret;
583 }
Taligned_malloc(size_t size,size_t alignment)584 void* Taligned_malloc(size_t size, size_t alignment)
585 {
586 void *ret = Raligned_malloc(size, alignment);
587 if (0 != ret)
588 ASSERT(0==((uintptr_t)ret & (alignment-1)),
589 "allocation result should be aligned");
590 return ret;
591 }
Taligned_realloc(void * memblock,size_t size,size_t alignment)592 void* Taligned_realloc(void* memblock, size_t size, size_t alignment)
593 {
594 void *ret = Raligned_realloc(memblock, size, alignment);
595 if (0 != ret)
596 ASSERT(0==((uintptr_t)ret & (alignment-1)),
597 "allocation result should be aligned");
598 return ret;
599 }
600
601 struct PtrSize {
602 void *ptr;
603 size_t size;
604 };
605
cmpAddrs(const void * p1,const void * p2)606 static int cmpAddrs(const void *p1, const void *p2)
607 {
608 const PtrSize *a = (const PtrSize *)p1;
609 const PtrSize *b = (const PtrSize *)p2;
610
611 return a->ptr < b->ptr ? -1 : ( a->ptr == b->ptr ? 0 : 1);
612 }
613
AddrArifm()614 void CMemTest::AddrArifm()
615 {
616 PtrSize *arr = (PtrSize*)Tmalloc(COUNT_ELEM*sizeof(PtrSize));
617
618 if (FullLog) REPORT("\nUnique pointer using Address arithmetic\n");
619 if (FullLog) REPORT("malloc....");
620 ASSERT(arr, NULL);
621 for (int i=0; i<COUNT_ELEM; i++)
622 {
623 arr[i].size=rand()%MAX_SIZE;
624 arr[i].ptr=Tmalloc(arr[i].size);
625 }
626 qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs);
627
628 for (int i=0; i<COUNT_ELEM-1; i++)
629 {
630 if (NULL!=arr[i].ptr && NULL!=arr[i+1].ptr)
631 ASSERT((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr,
632 "intersection detected");
633 }
634 //----------------------------------------------------------------
635 if (FullLog) REPORT("realloc....");
636 for (int i=0; i<COUNT_ELEM; i++)
637 {
638 size_t count=arr[i].size*2;
639 void *tmpAddr=Trealloc(arr[i].ptr,count);
640 if (NULL!=tmpAddr) {
641 arr[i].ptr = tmpAddr;
642 arr[i].size = count;
643 } else if (count==0) { // because realloc(..., 0) works as free
644 arr[i].ptr = NULL;
645 arr[i].size = 0;
646 }
647 }
648 qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs);
649
650 for (int i=0; i<COUNT_ELEM-1; i++)
651 {
652 if (NULL!=arr[i].ptr && NULL!=arr[i+1].ptr)
653 ASSERT((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr,
654 "intersection detected");
655 }
656 for (int i=0; i<COUNT_ELEM; i++)
657 {
658 Tfree(arr[i].ptr);
659 }
660 //-------------------------------------------
661 if (FullLog) REPORT("calloc....");
662 for (int i=0; i<COUNT_ELEM; i++)
663 {
664 arr[i].size=rand()%MAX_SIZE;
665 arr[i].ptr=Tcalloc(arr[i].size,1);
666 }
667 qsort(arr, COUNT_ELEM, sizeof(PtrSize), cmpAddrs);
668
669 for (int i=0; i<COUNT_ELEM-1; i++)
670 {
671 if (NULL!=arr[i].ptr && NULL!=arr[i+1].ptr)
672 ASSERT((uintptr_t)arr[i].ptr+arr[i].size <= (uintptr_t)arr[i+1].ptr,
673 "intersection detected");
674 }
675 for (int i=0; i<COUNT_ELEM; i++)
676 {
677 Tfree(arr[i].ptr);
678 }
679 Tfree(arr);
680 }
681
Zerofilling()682 void CMemTest::Zerofilling()
683 {
684 TestStruct* TSMas;
685 size_t CountElement;
686 CountErrors=0;
687 if (FullLog) REPORT("\nzeroings elements of array....");
688 //test struct
689 for (int i=0; i<COUNTEXPERIMENT; i++)
690 {
691 CountElement=rand()%MAX_SIZE;
692 TSMas=(TestStruct*)Tcalloc(CountElement,sizeof(TestStruct));
693 if (NULL == TSMas)
694 continue;
695 for (size_t j=0; j<CountElement; j++)
696 {
697 if (NonZero(TSMas+j, sizeof(TestStruct)))
698 {
699 CountErrors++;
700 if (ShouldReportError()) REPORT("detect nonzero element at TestStruct\n");
701 }
702 }
703 Tfree(TSMas);
704 }
705 if (CountErrors) REPORT("%s\n",strError);
706 else if (FullLog) REPORT("%s\n",strOk);
707 error_occurred |= ( CountErrors>0 ) ;
708 }
709
710 #if !__APPLE__
711
myMemset(void * ptr,int c,size_t n)712 void myMemset(void *ptr, int c, size_t n)
713 {
714 #if __linux__ && __i386__
715 // memset in Fedora 13 not always correctly sets memory to required values.
716 char *p = (char*)ptr;
717 for (size_t i=0; i<n; i++)
718 p[i] = c;
719 #else
720 memset(ptr, c, n);
721 #endif
722 }
723
724 // This test requires more than TOTAL_MB_ALLOC MB of RAM.
725 #if __ANDROID__
726 // Android requires lower limit due to lack of virtual memory.
727 #define TOTAL_MB_ALLOC 200
728 #else
729 #define TOTAL_MB_ALLOC 800
730 #endif
NULLReturn(UINT MinSize,UINT MaxSize,int total_threads)731 void CMemTest::NULLReturn(UINT MinSize, UINT MaxSize, int total_threads)
732 {
733 const int MB_PER_THREAD = TOTAL_MB_ALLOC / total_threads;
734 // find size to guarantee getting NULL for 1024 B allocations
735 const int MAXNUM_1024 = (MB_PER_THREAD + (MB_PER_THREAD>>2)) * 1024;
736
737 std::vector<MemStruct> PointerList;
738 void *tmp;
739 CountErrors=0;
740 int CountNULL, num_1024;
741 if (FullLog) REPORT("\nNULL return & check errno:\n");
742 UINT Size;
743 Limit limit_total(TOTAL_MB_ALLOC), no_limit(0);
744 void **buf_1024 = (void**)Tmalloc(MAXNUM_1024*sizeof(void*));
745
746 ASSERT(buf_1024, NULL);
747 /* We must have space for pointers when memory limit is hit.
748 Reserve enough for the worst case, taking into account race for
749 limited space between threads.
750 */
751 PointerList.reserve(TOTAL_MB_ALLOC*MByte/MinSize);
752
753 /* There is a bug in the specific version of GLIBC (2.5-12) shipped
754 with RHEL5 that leads to erroneous working of the test
755 on Intel(R) 64 and Itanium(R) architecture when setrlimit-related part is enabled.
756 Switching to GLIBC 2.5-18 from RHEL5.1 resolved the issue.
757 */
758 if (perProcessLimits)
759 limitBarrier->wait(limit_total);
760 else
761 limitMem(MB_PER_THREAD);
762
763 /* regression test against the bug in allocator when it dereference NULL
764 while lack of memory
765 */
766 for (num_1024=0; num_1024<MAXNUM_1024; num_1024++) {
767 buf_1024[num_1024] = Tcalloc(1024, 1);
768 if (! buf_1024[num_1024]) {
769 ASSERT_ERRNO(errno == ENOMEM, NULL);
770 break;
771 }
772 }
773 for (int i=0; i<num_1024; i++)
774 Tfree(buf_1024[i]);
775 Tfree(buf_1024);
776
777 do {
778 Size=rand()%(MaxSize-MinSize)+MinSize;
779 tmp=Tmalloc(Size);
780 if (tmp != NULL)
781 {
782 myMemset(tmp, 0, Size);
783 PointerList.push_back(MemStruct(tmp, Size));
784 }
785 } while(tmp != NULL);
786 ASSERT_ERRNO(errno == ENOMEM, NULL);
787 if (FullLog) REPORT("\n");
788
789 // preparation complete, now running tests
790 // malloc
791 if (FullLog) REPORT("malloc....");
792 CountNULL = 0;
793 while (CountNULL==0)
794 for (int j=0; j<COUNT_TESTS; j++)
795 {
796 Size=rand()%(MaxSize-MinSize)+MinSize;
797 errno = ENOMEM+j+1;
798 tmp=Tmalloc(Size);
799 if (tmp == NULL)
800 {
801 CountNULL++;
802 if ( CHECK_ERRNO(errno != ENOMEM) ) {
803 CountErrors++;
804 if (ShouldReportError()) REPORT("NULL returned, error: errno (%d) != ENOMEM\n", errno);
805 }
806 }
807 else
808 {
809 // Technically, if malloc returns a non-NULL pointer, it is allowed to set errno anyway.
810 // However, on most systems it does not set errno.
811 bool known_issue = false;
812 #if __linux__ || __ANDROID__
813 if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true;
814 #endif /* __linux__ */
815 if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue) {
816 CountErrors++;
817 if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno);
818 }
819 myMemset(tmp, 0, Size);
820 PointerList.push_back(MemStruct(tmp, Size));
821 }
822 }
823 if (FullLog) REPORT("end malloc\n");
824 if (CountErrors) REPORT("%s\n",strError);
825 else if (FullLog) REPORT("%s\n",strOk);
826 error_occurred |= ( CountErrors>0 ) ;
827
828 CountErrors=0;
829 //calloc
830 if (FullLog) REPORT("calloc....");
831 CountNULL = 0;
832 while (CountNULL==0)
833 for (int j=0; j<COUNT_TESTS; j++)
834 {
835 Size=rand()%(MaxSize-MinSize)+MinSize;
836 errno = ENOMEM+j+1;
837 tmp=Tcalloc(COUNT_ELEM_CALLOC,Size);
838 if (tmp == NULL)
839 {
840 CountNULL++;
841 if ( CHECK_ERRNO(errno != ENOMEM) ){
842 CountErrors++;
843 if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno);
844 }
845 }
846 else
847 {
848 // Technically, if calloc returns a non-NULL pointer, it is allowed to set errno anyway.
849 // However, on most systems it does not set errno.
850 bool known_issue = false;
851 #if __linux__
852 if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true;
853 #endif /* __linux__ */
854 if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue ) {
855 CountErrors++;
856 if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno);
857 }
858 PointerList.push_back(MemStruct(tmp, Size));
859 }
860 }
861 if (FullLog) REPORT("end calloc\n");
862 if (CountErrors) REPORT("%s\n",strError);
863 else if (FullLog) REPORT("%s\n",strOk);
864 error_occurred |= ( CountErrors>0 ) ;
865 CountErrors=0;
866 if (FullLog) REPORT("realloc....");
867 CountNULL = 0;
868 if (PointerList.size() > 0)
869 while (CountNULL==0)
870 for (size_t i=0; i<(size_t)COUNT_TESTS && i<PointerList.size(); i++)
871 {
872 errno = 0;
873 tmp=Trealloc(PointerList[i].Pointer,PointerList[i].Size*2);
874 if (tmp != NULL) // same or another place
875 {
876 bool known_issue = false;
877 #if __linux__
878 if( errno==ENOMEM ) known_issue = true;
879 #endif /* __linux__ */
880 if (errno != 0 && !known_issue) {
881 CountErrors++;
882 if (ShouldReportError()) REPORT("valid pointer returned, error: errno not kept\n");
883 }
884 // newly allocated area have to be zeroed
885 myMemset((char*)tmp + PointerList[i].Size, 0, PointerList[i].Size);
886 PointerList[i].Pointer = tmp;
887 PointerList[i].Size *= 2;
888 } else {
889 CountNULL++;
890 if ( CHECK_ERRNO(errno != ENOMEM) )
891 {
892 CountErrors++;
893 if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno);
894 }
895 // check data integrity
896 if (NonZero(PointerList[i].Pointer, PointerList[i].Size)) {
897 CountErrors++;
898 if (ShouldReportError()) REPORT("NULL returned, error: data changed\n");
899 }
900 }
901 }
902 if (FullLog) REPORT("realloc end\n");
903 if (CountErrors) REPORT("%s\n",strError);
904 else if (FullLog) REPORT("%s\n",strOk);
905 error_occurred |= ( CountErrors>0 ) ;
906 for (UINT i=0; i<PointerList.size(); i++)
907 {
908 Tfree(PointerList[i].Pointer);
909 }
910
911 if (perProcessLimits)
912 limitBarrier->wait(no_limit);
913 else
914 limitMem(0);
915 }
916 #endif /* #if !__APPLE__ */
917
UniquePointer()918 void CMemTest::UniquePointer()
919 {
920 CountErrors=0;
921 int **MasPointer = (int **)Tmalloc(sizeof(int*)*COUNT_ELEM);
922 size_t *MasCountElem = (size_t*)Tmalloc(sizeof(size_t)*COUNT_ELEM);
923 if (FullLog) REPORT("\nUnique pointer using 0\n");
924 ASSERT(MasCountElem && MasPointer, NULL);
925 //
926 //-------------------------------------------------------
927 //malloc
928 for (int i=0; i<COUNT_ELEM; i++)
929 {
930 MasCountElem[i]=rand()%MAX_SIZE;
931 MasPointer[i]=(int*)Tmalloc(MasCountElem[i]*sizeof(int));
932 if (NULL == MasPointer[i])
933 MasCountElem[i]=0;
934 memset(MasPointer[i], 0, sizeof(int)*MasCountElem[i]);
935 }
936 if (FullLog) REPORT("malloc....");
937 for (UINT i=0; i<COUNT_ELEM-1; i++)
938 {
939 if (size_t badOff = NonZero(MasPointer[i], sizeof(int)*MasCountElem[i])) {
940 CountErrors++;
941 if (ShouldReportError())
942 REPORT("error, detect non-zero at %p\n", (char*)MasPointer[i]+badOff-1);
943 }
944 memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]);
945 }
946 if (CountErrors) REPORT("%s\n",strError);
947 else if (FullLog) REPORT("%s\n",strOk);
948 error_occurred |= ( CountErrors>0 ) ;
949 //----------------------------------------------------------
950 //calloc
951 for (int i=0; i<COUNT_ELEM; i++)
952 Tfree(MasPointer[i]);
953 CountErrors=0;
954 for (long i=0; i<COUNT_ELEM; i++)
955 {
956 MasPointer[i]=(int*)Tcalloc(MasCountElem[i]*sizeof(int),2);
957 if (NULL == MasPointer[i])
958 MasCountElem[i]=0;
959 }
960 if (FullLog) REPORT("calloc....");
961 for (int i=0; i<COUNT_ELEM-1; i++)
962 {
963 if (size_t badOff = NonZero(MasPointer[i], sizeof(int)*MasCountElem[i])) {
964 CountErrors++;
965 if (ShouldReportError())
966 REPORT("error, detect non-zero at %p\n", (char*)MasPointer[i]+badOff-1);
967 }
968 memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]);
969 }
970 if (CountErrors) REPORT("%s\n",strError);
971 else if (FullLog) REPORT("%s\n",strOk);
972 error_occurred |= ( CountErrors>0 ) ;
973 //---------------------------------------------------------
974 //realloc
975 CountErrors=0;
976 for (int i=0; i<COUNT_ELEM; i++)
977 {
978 MasCountElem[i]*=2;
979 *(MasPointer+i)=
980 (int*)Trealloc(*(MasPointer+i),MasCountElem[i]*sizeof(int));
981 if (NULL == MasPointer[i])
982 MasCountElem[i]=0;
983 memset(MasPointer[i], 0, sizeof(int)*MasCountElem[i]);
984 }
985 if (FullLog) REPORT("realloc....");
986 for (int i=0; i<COUNT_ELEM-1; i++)
987 {
988 if (NonZero(MasPointer[i], sizeof(int)*MasCountElem[i]))
989 CountErrors++;
990 memset(MasPointer[i], 1, sizeof(int)*MasCountElem[i]);
991 }
992 if (CountErrors) REPORT("%s\n",strError);
993 else if (FullLog) REPORT("%s\n",strOk);
994 error_occurred |= ( CountErrors>0 ) ;
995 for (int i=0; i<COUNT_ELEM; i++)
996 Tfree(MasPointer[i]);
997 Tfree(MasCountElem);
998 Tfree(MasPointer);
999 }
1000
ShouldReportError()1001 bool CMemTest::ShouldReportError()
1002 {
1003 if (FullLog)
1004 return true;
1005 else
1006 if (firstTime) {
1007 firstTime = false;
1008 return true;
1009 } else
1010 return false;
1011 }
1012
Free_NULL()1013 void CMemTest::Free_NULL()
1014 {
1015 CountErrors=0;
1016 if (FullLog) REPORT("\ncall free with parameter NULL....");
1017 errno = 0;
1018 for (int i=0; i<COUNTEXPERIMENT; i++)
1019 {
1020 Tfree(NULL);
1021 if (CHECK_ERRNO(errno))
1022 {
1023 CountErrors++;
1024 if (ShouldReportError()) REPORT("error is found by a call free with parameter NULL\n");
1025 }
1026 }
1027 if (CountErrors) REPORT("%s\n",strError);
1028 else if (FullLog) REPORT("%s\n",strOk);
1029 error_occurred |= ( CountErrors>0 ) ;
1030 }
1031
TestAlignedParameters()1032 void CMemTest::TestAlignedParameters()
1033 {
1034 void *memptr;
1035 int ret;
1036
1037 if (Rposix_memalign) {
1038 // alignment isn't power of 2
1039 for (int bad_align=3; bad_align<16; bad_align++)
1040 if (bad_align&(bad_align-1)) {
1041 ret = Tposix_memalign(NULL, bad_align, 100);
1042 ASSERT(EINVAL==ret, NULL);
1043 }
1044
1045 memptr = &ret;
1046 ret = Tposix_memalign(&memptr, 5*sizeof(void*), 100);
1047 ASSERT(memptr == &ret,
1048 "memptr should not be changed after unsuccessful call");
1049 ASSERT(EINVAL==ret, NULL);
1050
1051 // alignment is power of 2, but not a multiple of sizeof(void *),
1052 // we expect that sizeof(void*) > 2
1053 ret = Tposix_memalign(NULL, 2, 100);
1054 ASSERT(EINVAL==ret, NULL);
1055 }
1056 if (Raligned_malloc) {
1057 // alignment isn't power of 2
1058 for (int bad_align=3; bad_align<16; bad_align++)
1059 if (bad_align&(bad_align-1)) {
1060 memptr = Taligned_malloc(100, bad_align);
1061 ASSERT(NULL==memptr, NULL);
1062 ASSERT_ERRNO(EINVAL==errno, NULL);
1063 }
1064
1065 // size is zero
1066 memptr = Taligned_malloc(0, 16);
1067 ASSERT(NULL==memptr, "size is zero, so must return NULL");
1068 ASSERT_ERRNO(EINVAL==errno, NULL);
1069 }
1070 if (Taligned_free) {
1071 // NULL pointer is OK to free
1072 errno = 0;
1073 Taligned_free(NULL);
1074 /* As there is no return value for free, strictly speaking we can't
1075 check errno here. But checked implementations obey the assertion.
1076 */
1077 ASSERT_ERRNO(0==errno, NULL);
1078 }
1079 if (Raligned_realloc) {
1080 for (int i=1; i<20; i++) {
1081 // checks that calls work correctly in presence of non-zero errno
1082 errno = i;
1083 void *ptr = Taligned_malloc(i*10, 128);
1084 ASSERT(NULL!=ptr, NULL);
1085 ASSERT_ERRNO(0!=errno, NULL);
1086 // if size is zero and pointer is not NULL, works like free
1087 memptr = Taligned_realloc(ptr, 0, 64);
1088 ASSERT(NULL==memptr, NULL);
1089 ASSERT_ERRNO(0!=errno, NULL);
1090 }
1091 // alignment isn't power of 2
1092 for (int bad_align=3; bad_align<16; bad_align++)
1093 if (bad_align&(bad_align-1)) {
1094 void *ptr = &bad_align;
1095 memptr = Taligned_realloc(&ptr, 100, bad_align);
1096 ASSERT(NULL==memptr, NULL);
1097 ASSERT(&bad_align==ptr, NULL);
1098 ASSERT_ERRNO(EINVAL==errno, NULL);
1099 }
1100 }
1101 }
1102
RunAllTests(int total_threads)1103 void CMemTest::RunAllTests(int total_threads)
1104 {
1105 Zerofilling();
1106 Free_NULL();
1107 InvariantDataRealloc(/*aligned=*/false, 8*MByte, /*checkData=*/true);
1108 if (Raligned_realloc)
1109 InvariantDataRealloc(/*aligned=*/true, 8*MByte, /*checkData=*/true);
1110 TestAlignedParameters();
1111 UniquePointer();
1112 AddrArifm();
1113 #if __APPLE__
1114 REPORT("Known issue: some tests are skipped on macOS\n");
1115 #else
1116 NULLReturn(1*MByte,100*MByte,total_threads);
1117 #endif
1118 if (FullLog) REPORT("Tests for %d threads ended\n", total_threads);
1119 }
1120
1121 #endif /* __TBB_WIN8UI_SUPPORT */
1122