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;
}
Exemplo n.º 4
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;
}