关闭

vc++多线程随机单元测试实例之测试vld库

331人阅读 评论(0) 收藏 举报
分类:
////////////////////////////////////////////////////////////////////////////////
//
//  Visual Leak Detector - Test Suite
//  Copyright (c) 2009 Dan Moulding
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//
//  See COPYING.txt for the full terms of the GNU Lesser General Public License.
//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//
//  Test suite for Visual Leak Detector
//
////////////////////////////////////////////////////////////////////////////////

#include <cassert>
#include <cstdio>
#include <windows.h>

#include <vld.h>

enum action_e {
    a_calloc,
    a_comalloc,
    a_getprocmalloc,
    a_heapalloc,
    a_icomalloc,
    a_ignored,
    a_malloc,
    a_new,
    numactions
};
//我这里是vs2013
#define CRTDLLNAME   "msvcr120d.dll"          // Name of the debug C Runtime Library DLL on this system
#define MAXALLOC     1000                    // Maximum number of allocations of each type to perform, per thread
#define MAXBLOCKS    (MAXALLOC * numactions) // Total maximum number of allocations, per thread
#define MAXDEPTH     32                      // Maximum depth of the allocation call stack
#define MAXSIZE      64                      // Maximum block size to allocate
#define MINDEPTH     0                       // Minimum depth of the allocation call stack
#define MINSIZE      16                      // Minimum block size to allocate
#define NUMDUPLEAKS  0                       // Number of times to duplicate each leak
#define NUMTHREADS   72                      // Number of threads to run simultaneously
#define ONCEINAWHILE 10                      // Free a random block approx. once every...

typedef struct blockholder_s {
    action_e action;
    PVOID    block;
    BOOL     leak;
} blockholder_t;

typedef void* (__cdecl *free_t) (void* mem);
typedef void* (__cdecl *malloc_t) (size_t size);

typedef struct threadcontext_s {
    UINT  index;
    BOOL  leaky;
    DWORD seed;
    BOOL  terminated;
    DWORD threadid;
} threadcontext_t;

__declspec(thread) blockholder_t  blocks [MAXBLOCKS];
__declspec(thread) ULONG          counts [numactions] = { 0 };
__declspec(thread) IMalloc       *imalloc = NULL;
__declspec(thread) free_t         pfree = NULL;
__declspec(thread) malloc_t       pmalloc = NULL;
__declspec(thread) HANDLE         threadheap;
__declspec(thread) ULONG          total_allocs = 0;

ULONG random (ULONG max)
{
    FLOAT d;
    FLOAT r;
    ULONG v;

    r = ((FLOAT)rand()) / ((FLOAT)RAND_MAX);
    r *= ((FLOAT)max);
    d = r - ((ULONG)r);
    if (d >= 0.5) {
        v = ((ULONG)r) + 1;
    }
    else {
        v = (ULONG)r;
    }

    return v;
}

VOID allocateblock (action_e action, SIZE_T size)
{
    HMODULE  crt;
    ULONG    index;
    LPCSTR   name;
    PVOID   *pblock;
    HRESULT  status;

    // Find the first unused index.
    for (index = 0; index < MAXBLOCKS; index++) {
        if (blocks[index].block == NULL) {
            break;
        }
    }
    blocks[index].action = action;

    // Now do the randomized allocation.        
    pblock = &blocks[index].block;
    switch (action) {
        case a_calloc:
            name = "calloc";
            *pblock = calloc(1, size);
            break;

        case a_comalloc:
            name = "CoTaskMemAlloc";
            *pblock = CoTaskMemAlloc(size);
            break;

        case a_getprocmalloc:
            name = "GetProcAddress";
            if (pmalloc == NULL) {
                crt = LoadLibrary(CRTDLLNAME);
                assert(crt != NULL);
                pmalloc = (malloc_t)GetProcAddress(crt, "malloc");
                assert(pmalloc !=  NULL);
            }
            *pblock = pmalloc(size);
            break;

        case a_heapalloc:
            name = "HeapAlloc";
            if (threadheap == NULL) {
                threadheap = HeapCreate(0x0, 0, 0);
            }
            *pblock = HeapAlloc(threadheap, 0x0, size);
            break;

        case a_icomalloc:
            name = "IMalloc";
            if (imalloc == NULL) {
                status = CoGetMalloc(1, &imalloc);
                assert(status == S_OK);
            }
            *pblock = imalloc->Alloc(size);
            break;

        case a_ignored:
            name = "Ignored";
            VLDDisable();
            *pblock = malloc(size);
            VLDEnable();
            break;

        case a_malloc:
            name = "malloc";
            *pblock = malloc(size);
            break;

        case a_new:
            name = "new";
            *pblock = new BYTE [size];
            break;

        default:
            assert(FALSE);
    }
    counts[action]++;
    total_allocs++;

    strncpy_s((char*)*pblock, size, name, _TRUNCATE);
}

VOID freeblock (ULONG index)
{
    PVOID   block;
    HMODULE crt;

    block = blocks[index].block;
    switch (blocks[index].action) {
        case a_calloc:
            free(block);
            break;

        case a_comalloc:
            CoTaskMemFree(block);
            break;

        case a_getprocmalloc:
            if (pfree == NULL) {
                crt = GetModuleHandle(CRTDLLNAME);
                assert(crt != NULL);
                pfree = (free_t)GetProcAddress(crt, "free");
                assert(pfree != NULL);
            }
            pfree(block);
            break;

        case a_heapalloc:
            HeapFree(threadheap, 0x0, block);
            break;

        case a_icomalloc:
            imalloc->Free(block);
            break;

        case a_ignored:
            free(block);
            break;
            
        case a_malloc:
            free(block);
            break;

        case a_new:
            delete [] block;
            break;

        default:
            assert(FALSE);
    }
    blocks[index].block = NULL;
    counts[blocks[index].action]--;
    total_allocs--;
}

VOID recursivelyallocate (UINT depth, action_e action, SIZE_T size)
{
    if (depth == 0) {
        allocateblock(action, size);
    }
    else {
        recursivelyallocate(depth - 1, action, size);
    }
}

DWORD __stdcall runtestsuite (LPVOID param)
{
    action_e         action;
    USHORT           action_index;
    BOOL             allocate_more = TRUE;
    threadcontext_t *context = (threadcontext_t*)param;
    UINT             depth;
    ULONG            index;
    UINT             leaks_selected;
    SIZE_T           size;

    srand(context->seed);

    for (index = 0; index < MAXBLOCKS; index++) {
        blocks[index].block = NULL;
        blocks[index].leak = FALSE;
    }

    while (allocate_more == TRUE) {
        // Select a random allocation action and a random size.
        action = (action_e)random(numactions - 1);
        size = random(MAXSIZE);
        if (size < MINSIZE) {
            size = MINSIZE;
        }
        if (counts[action] == MAXALLOC) {
            // We've done enough of this type of allocation. Select another.
            continue;
        }

        // Allocate a block, using recursion to build up a stack of random
        // depth.
        depth = random(MAXDEPTH);
        if (depth < MINDEPTH) {
            depth = MINDEPTH;
        }
        recursivelyallocate(depth, action, size);

        // Every once in a while, free a random block.
        if (random(ONCEINAWHILE) == ONCEINAWHILE) {
            index = random(total_allocs);
            if (blocks[index].block != NULL) {
                freeblock(index);
            }
        }

        // See if we have allocated enough blocks using each type of action.
        for (action_index = 0; action_index < numactions; action_index++) {
            if (counts[action_index] < MAXALLOC) {
                allocate_more = TRUE;
                break;
            }
            allocate_more = FALSE;
        }
    }

    if (context->leaky == TRUE) {
        // This is the leaky thread. Randomly select one block to be leaked from
        // each type of allocation action.
        for (action_index = 0; action_index < numactions; action_index++) {
            leaks_selected = 0;
            do {
                index = random(MAXBLOCKS);
                if ((blocks[index].block != NULL) && (blocks[index].action == (action_e)action_index)) {
                    blocks[index].leak = TRUE;
                    leaks_selected++;
                }
            } while (leaks_selected < (1 + NUMDUPLEAKS));
        }
    }

    // Free all blocks except for those marked as leaks.
    for (index = 0; index < MAXBLOCKS; index++) {
        if ((blocks[index].block != NULL) && (blocks[index].leak == FALSE)) {
            freeblock(index);
        }
    }

    // Do a sanity check.
    if (context->leaky == TRUE) {
        assert(total_allocs == (numactions * (1 + NUMDUPLEAKS)));
    }
    else {
        assert(total_allocs == 0);
    }

    context->terminated = TRUE;
	printf("pid=%d tid=%d run runtestsuite finish!\n",GetCurrentProcessId(),GetCurrentThreadId());
    return 0;
}
//vc++多线程随机单元测试实例之测试vld库。
int main (int argc, char *argv [])
{
    threadcontext_t contexts [NUMTHREADS];
    DWORD           end;
    UINT            index;
#define MESSAGESIZE 512
    char            message [512];
    DWORD           start;
    UINT            leakythread;

    start = GetTickCount();
    srand(start);

    // Select a random thread to be the leaker.
    leakythread = random(NUMTHREADS - 1);

    for (index = 0; index < NUMTHREADS; ++index) {
        contexts[index].index = index;
        if (index == leakythread) {
            contexts[index].leaky = TRUE;
        }
        contexts[index].seed = random(RAND_MAX);
        contexts[index].terminated = FALSE;
        CreateThread(NULL, 0, runtestsuite, &contexts[index], 0, &contexts[index].threadid);
    }

    // Wait for all threads to terminate.
    for (index = 0; index < NUMTHREADS; ++index) {
        while (contexts[index].terminated == FALSE) {
            Sleep(10);
        }
    }

    end = GetTickCount();
    _snprintf_s(message, 512, _TRUNCATE, "Elapsed Time = %ums\n", end - start);
    OutputDebugString(message);
	printf(message);
	//printf("random=%lu", random(15));

    return 0;
}

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1691089次
    • 积分:24482
    • 等级:
    • 排名:第248名
    • 原创:780篇
    • 转载:383篇
    • 译文:0篇
    • 评论:215条
    我的技术博客
    最新评论