void CMemTest::NULLReturn(UINT MinSize, UINT MaxSize, int total_threads) { const int MB_PER_THREAD = TOTAL_MB_ALLOC / total_threads; // find size to guarantee getting NULL for 1024 B allocations const int MAXNUM_1024 = (MB_PER_THREAD + (MB_PER_THREAD>>2)) * 1024; std::vector<MemStruct> PointerList; void *tmp; CountErrors=0; int CountNULL, num_1024; if (FullLog) REPORT("\nNULL return & check errno:\n"); UINT Size; Limit limit_total(TOTAL_MB_ALLOC), no_limit(0); void **buf_1024 = (void**)Tmalloc(MAXNUM_1024*sizeof(void*)); ASSERT(buf_1024, NULL); /* We must have space for pointers when memory limit is hit. Reserve enough for the worst case, taking into account race for limited space between threads. */ PointerList.reserve(TOTAL_MB_ALLOC*MByte/MinSize); /* There is a bug in the specific version of GLIBC (2.5-12) shipped with RHEL5 that leads to erroneous working of the test on Intel64 and IPF systems when setrlimit-related part is enabled. Switching to GLIBC 2.5-18 from RHEL5.1 resolved the issue. */ if (perProcessLimits) limitBarrier->wait(limit_total); else limitMem(MB_PER_THREAD); /* regression test against the bug in allocator when it dereference NULL while lack of memory */ for (num_1024=0; num_1024<MAXNUM_1024; num_1024++) { buf_1024[num_1024] = Tcalloc(1024, 1); if (! buf_1024[num_1024]) { ASSERT_ERRNO(errno == ENOMEM, NULL); break; } } for (int i=0; i<num_1024; i++) Tfree(buf_1024[i]); Tfree(buf_1024); do { Size=rand()%(MaxSize-MinSize)+MinSize; tmp=Tmalloc(Size); if (tmp != NULL) { myMemset(tmp, 0, Size); PointerList.push_back(MemStruct(tmp, Size)); } } while(tmp != NULL); ASSERT_ERRNO(errno == ENOMEM, NULL); if (FullLog) REPORT("\n"); // preparation complete, now running tests // malloc if (FullLog) REPORT("malloc...."); CountNULL = 0; while (CountNULL==0) for (int j=0; j<COUNT_TESTS; j++) { Size=rand()%(MaxSize-MinSize)+MinSize; errno = ENOMEM+j+1; tmp=Tmalloc(Size); if (tmp == NULL) { CountNULL++; if ( CHECK_ERRNO(errno != ENOMEM) ) { CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: errno (%d) != ENOMEM\n", errno); } } else { // Technically, if malloc returns a non-NULL pointer, it is allowed to set errno anyway. // However, on most systems it does not set errno. bool known_issue = false; #if __linux__ if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true; #endif /* __linux__ */ if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue) { CountErrors++; if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno); } myMemset(tmp, 0, Size); PointerList.push_back(MemStruct(tmp, Size)); } } if (FullLog) REPORT("end malloc\n"); if (CountErrors) REPORT("%s\n",strError); else if (FullLog) REPORT("%s\n",strOk); error_occurred |= ( CountErrors>0 ) ; CountErrors=0; //calloc if (FullLog) REPORT("calloc...."); CountNULL = 0; while (CountNULL==0) for (int j=0; j<COUNT_TESTS; j++) { Size=rand()%(MaxSize-MinSize)+MinSize; errno = ENOMEM+j+1; tmp=Tcalloc(COUNT_ELEM_CALLOC,Size); if (tmp == NULL) { CountNULL++; if ( CHECK_ERRNO(errno != ENOMEM) ){ CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno); } } else { // Technically, if calloc returns a non-NULL pointer, it is allowed to set errno anyway. // However, on most systems it does not set errno. bool known_issue = false; #if __linux__ if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true; #endif /* __linux__ */ if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue ) { CountErrors++; if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno); } PointerList.push_back(MemStruct(tmp, Size)); } } if (FullLog) REPORT("end calloc\n"); if (CountErrors) REPORT("%s\n",strError); else if (FullLog) REPORT("%s\n",strOk); error_occurred |= ( CountErrors>0 ) ; CountErrors=0; if (FullLog) REPORT("realloc...."); CountNULL = 0; if (PointerList.size() > 0) while (CountNULL==0) for (size_t i=0; i<(size_t)COUNT_TESTS && i<PointerList.size(); i++) { errno = 0; tmp=Trealloc(PointerList[i].Pointer,PointerList[i].Size*2); if (PointerList[i].Pointer == tmp) // the same place { bool known_issue = false; #if __linux__ if( errno==ENOMEM ) known_issue = true; #endif /* __linux__ */ if (errno != 0 && !known_issue) { CountErrors++; if (ShouldReportError()) REPORT("valid pointer returned, error: errno not kept\n"); } PointerList[i].Size *= 2; } else if (tmp != PointerList[i].Pointer && tmp != NULL) // another place { bool known_issue = false; #if __linux__ if( errno==ENOMEM ) known_issue = true; #endif /* __linux__ */ if (errno != 0 && !known_issue) { CountErrors++; if (ShouldReportError()) REPORT("valid pointer returned, error: errno not kept\n"); } // newly allocated area have to be zeroed myMemset((char*)tmp + PointerList[i].Size, 0, PointerList[i].Size); PointerList[i].Pointer = tmp; PointerList[i].Size *= 2; } else if (tmp == NULL) { CountNULL++; if ( CHECK_ERRNO(errno != ENOMEM) ) { CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno); } // check data integrity if (NonZero(PointerList[i].Pointer, PointerList[i].Size)) { CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: data changed\n"); } } } if (FullLog) REPORT("realloc end\n"); if (CountErrors) REPORT("%s\n",strError); else if (FullLog) REPORT("%s\n",strOk); error_occurred |= ( CountErrors>0 ) ; for (UINT i=0; i<PointerList.size(); i++) { Tfree(PointerList[i].Pointer); } if (perProcessLimits) limitBarrier->wait(no_limit); else limitMem(0); }
void operator() () const { limitMem(limit); }
HARNESS_EXPORT int main(int argc, char* argv[]) { argC=argc; argV=argv; MaxThread = MinThread = 1; Tmalloc=scalable_malloc; Trealloc=scalable_realloc; Tcalloc=scalable_calloc; Tfree=scalable_free; Rposix_memalign=scalable_posix_memalign; Raligned_malloc=scalable_aligned_malloc; Raligned_realloc=scalable_aligned_realloc; Taligned_free=scalable_aligned_free; // check if we were called to test standard behavior for (int i=1; i< argc; i++) { if (strcmp((char*)*(argv+i),"-s")==0) { setSystemAllocs(); argC--; break; } } ParseCommandLine( argC, argV ); #if __linux__ /* According to man pthreads "NPTL threads do not share resource limits (fixed in kernel 2.6.10)". Use per-threads limits for affected systems. */ if ( LinuxKernelVersion() < 2*1000000 + 6*1000 + 10) perProcessLimits = false; #endif //------------------------------------- #if __APPLE__ /* Skip due to lack of memory limit enforcing under OS X*. */ #else limitMem(200); ReallocParam(); limitMem(0); #endif //for linux and dynamic runtime errno is used to check allocator functions //check if library compiled with /MD(d) and we can use errno #if _MSC_VER #if defined(_MT) && defined(_DLL) //check errno if test itself compiled with /MD(d) only char* version_info_block = NULL; int version_info_block_size; LPVOID comments_block = NULL; UINT comments_block_size; #ifdef _DEBUG #define __TBBMALLOCDLL "tbbmalloc_debug.dll" #else //_DEBUG #define __TBBMALLOCDLL "tbbmalloc.dll" #endif //_DEBUG version_info_block_size = GetFileVersionInfoSize( __TBBMALLOCDLL, (LPDWORD)&version_info_block_size ); if( version_info_block_size && ((version_info_block = (char*)malloc(version_info_block_size)) != NULL) && GetFileVersionInfo( __TBBMALLOCDLL, NULL, version_info_block_size, version_info_block ) && VerQueryValue( version_info_block, "\\StringFileInfo\\000004b0\\Comments", &comments_block, &comments_block_size ) && strstr( (char*)comments_block, "/MD" ) ){ __tbb_test_errno = true; } if( version_info_block ) free( version_info_block ); #endif // defined(_MT) && defined(_DLL) #else // _MSC_VER __tbb_test_errno = true; #endif // _MSC_VER for( int p=MaxThread; p>=MinThread; --p ) { REMARK("testing with %d threads\n", p ); Harness::SpinBarrier *barrier = new Harness::SpinBarrier(p); NativeParallelFor( p, RoundRobin(p, barrier, Verbose) ); delete barrier; } if( !error_occurred ) REPORT("done\n"); return 0; }
HARNESS_EXPORT int main(int argc, char* argv[]) { argC=argc; argV=argv; MaxThread = MinThread = 1; Rmalloc=scalable_malloc; Rrealloc=scalable_realloc; Rcalloc=scalable_calloc; Tfree=scalable_free; Rposix_memalign=scalable_posix_memalign; Raligned_malloc=scalable_aligned_malloc; Raligned_realloc=scalable_aligned_realloc; Taligned_free=scalable_aligned_free; // check if we were called to test standard behavior for (int i=1; i< argc; i++) { if (strcmp((char*)*(argv+i),"-s")==0) { #if __INTEL_COMPILER == 1400 && __linux__ // Workaround for Intel(R) C++ Compiler XE, version 14.0.0.080: // unable to call setSystemAllocs() in such configuration. REPORT("Known issue: Standard allocator testing is not supported.\n"); REPORT( "skip\n" ); return 0; #else setSystemAllocs(); argC--; break; #endif } } ParseCommandLine( argC, argV ); #if __linux__ /* According to man pthreads "NPTL threads do not share resource limits (fixed in kernel 2.6.10)". Use per-threads limits for affected systems. */ if ( LinuxKernelVersion() < 2*1000000 + 6*1000 + 10) perProcessLimits = false; #endif //------------------------------------- #if __APPLE__ /* Skip due to lack of memory limit enforcing under macOS. */ #else limitMem(200); ReallocParam(); limitMem(0); #endif //for linux and dynamic runtime errno is used to check allocator functions //check if library compiled with /MD(d) and we can use errno #if _MSC_VER #if defined(_MT) && defined(_DLL) //check errno if test itself compiled with /MD(d) only char* version_info_block = NULL; int version_info_block_size; LPVOID comments_block = NULL; UINT comments_block_size; #ifdef _DEBUG #define __TBBMALLOCDLL "tbbmalloc_debug.dll" #else //_DEBUG #define __TBBMALLOCDLL "tbbmalloc.dll" #endif //_DEBUG version_info_block_size = GetFileVersionInfoSize( __TBBMALLOCDLL, (LPDWORD)&version_info_block_size ); if( version_info_block_size && ((version_info_block = (char*)malloc(version_info_block_size)) != NULL) && GetFileVersionInfo( __TBBMALLOCDLL, NULL, version_info_block_size, version_info_block ) && VerQueryValue( version_info_block, "\\StringFileInfo\\000004b0\\Comments", &comments_block, &comments_block_size ) && strstr( (char*)comments_block, "/MD" ) ){ __tbb_test_errno = true; } if( version_info_block ) free( version_info_block ); #endif // defined(_MT) && defined(_DLL) #else // _MSC_VER __tbb_test_errno = true; #endif // _MSC_VER CheckArgumentsOverflow(); CheckReallocLeak(); for( int p=MaxThread; p>=MinThread; --p ) { REMARK("testing with %d threads\n", p ); for (int limit=0; limit<2; limit++) { int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT, 16*1024*limit); ASSERT(ret==TBBMALLOC_OK, NULL); Harness::SpinBarrier *barrier = new Harness::SpinBarrier(p); NativeParallelFor( p, RoundRobin(p, barrier, Verbose) ); delete barrier; } } int ret = scalable_allocation_mode(TBBMALLOC_SET_SOFT_HEAP_LIMIT, 0); ASSERT(ret==TBBMALLOC_OK, NULL); if( !error_occurred ) REPORT("done\n"); return 0; }