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

45 篇文章 1 订阅

//
//  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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
初识Visual Leak Detector   灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题。当程序越来越复杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题。内存泄漏是最常见的内存问题之一。内存泄漏如果不是很严重,在短时间内对程序不会有太大的影响,这也使得内存泄漏问题有很强的隐蔽性,不容易被发现。然而不管内存泄漏多么轻微,当程序长时间运行时,其破坏力是惊人的,从性能下降到内存耗尽,甚至会影响到其他程序的正常运行。另外内存问题的一个共同特点是,内存问题本身并不会有很明显的现象,当有异常现象出现时已时过境迁,其现场已非出现问题时的现场了,这给调试内存问题带来了很大的难度。   Visual Leak Detector是一款用于Visual C++的免费的内存泄露检测工具。相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点:   1、 可以得到内存泄漏点的调用堆栈,如果可以的话,还可以得到其所在文件及行号;   2、 可以得到泄露内存的完整数据;   3、 可以设置内存泄露报告的级别;   4、 它是一个已经打包的lib,使用时无须编译它的源代码。而对于使用者自己的代码,也只需要做很小的改动;   5、 他的源代码使用GNU许可发布,并有详尽的文档及注释。对于想深入了解堆内存管理的读者,是一个不错的选择。   可见,从使用角度来讲,Visual Leak Detector简单易用,对于使用者自己的代码,唯一的修改是#include Visual Leak Detector的头文件后正常运行自己的程序,就可以发现内存问题。从研究的角度来讲,如果深入Visual Leak Detector源代码,可以学习到堆内存分配与释放的原理、内存泄漏检测的原理及内存操作的常用技巧等。   本文首先将介绍Visual Leak Detector的使用方法与步骤,然后再和读者一起初步的研究Visual Leak Detector的源代码,去了解Visual Leak Detector的工作原理。   使用Visual Leak Detector(1.0)   下面让我们来介绍如何使用这个小巧的工具。   首先从网站上下载zip包,解压之后得到vld.h, vldapi.h, vld.lib, vldmt.lib, vldmtdll.lib, dbghelp.dll等文件。将.h文件拷贝到Visual C++的默认include目录下,将.lib文件拷贝到Visual C++的默认lib目录下,便安装完成了。因为版本问题,如果使用windows 2000或者以前的版本,需要将dbghelp.dll拷贝到你的程序的运行目录下,或其他可以引用到的目录。   接下来需要将其加入到自己的代码。方法很简单,只要在包含入口函数的.cpp文件包含vld.h就可以。如果这个cpp文件包含了stdafx.h,则将包含vld.h的语句放在stdafx.h的包含语句之后,否则放在最前面。如下是一个示例程序:   #include   void main()   {   …   }   接下来让我们来演示如何使用Visual Leak Detector检测内存泄漏。下面是一个简单的程序,用new分配了一个int大小的堆内存,并没有释放。其申请的内存地址用printf输出到屏幕上。   #include   #include   #include   void f()   {   int *p = new int(0x12345678);   printf("p=%08x, ", p);   }   void main()   {   f();   }   编译运行后,在标准输出窗口得到:   p=003a89c0   在Visual C++的Output窗口得到:   WARNING: Visual Leak Detector detected memory leaks!   ---------- Block 57 at 0x003A89C0: 4 bytes ---------- --57号块0x003A89C0地址泄漏了4个字节   Call Stack: --下面是调用堆栈   d:\test\testvldconsole\testvldconsole\main.cpp (7): f --表示在main.cpp第7行的f()函数   d:\test\testvldconsole\testvldconsole\main.cpp (14): main –双击以引导至对应代码处   f:\rtm\vctools\crt_bld\self_x8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值