0X01 关闭FPO优化

// Frame pointer omission (FPO) optimization should be turned off for this

// entire file. The release VLD libs don't include FPO debug information, so FPO

// optimization will interfere with stack walking.

#pragma optimize ("y", off)

Release版本的VLD库不包含FPO调试信息,进而影响栈回溯,所以文件开头关闭FPO优化;

0X02 内存泄漏检测器全局对象

// The one and only VisualLeakDetector object instance. This is placed in the

// "compiler" initialization area, so that it gets constructed during C runtime

// initialization and before any user global objects are constructed. Also,

// disable the warning about us using the "compiler" initialization area.

#pragma warning (disable:4074)

#pragma init_seg (compiler)

VisualLeakDetector visualleakdetector;

对于同一个文件来说,全局变量的构造顺序是按照全局变量的声明顺序来构造的。但对于不同文件来说,不同文件间的全局变量构造顺序是不确定的。在C++标准中,只要求“处于同一编译但与的全局对象按其声明顺序初始化并倒序析构”,但并没有对处于不同编译单元的全局对象的初始化顺序做出要求。

通过init_seg预处理器指令中,:

#pragma init_seg(compiler)

#pragma init_seg(lib)

#pragma init_seg(user)

#pragma init_seg("user_defined_segment_name")

编译器、库、用户和用户定义段,按顺序依次初始化(但据实测,用户和用户定义段的优先级相同);

注:一个源文件中只能出现一次init_seg指令;且编译器段是微软保留给C/C++运行时库用的,一般情况下我们不应该使用它。

VLD为了保证尽可能的全面诊断内存泄漏,势必需要在其他全局变量构造前完成初始化。VLD就利用init_seg了处理器指令,让VLD的VisualLeakDetector在绝大多数情况下早于其他全局变量进行构造和初始化,即上面的实现。

#pragma warning (disable:4074):用于屏蔽C4074编译器警告,否则编译时会提示:warning C4074: initializers put in compiler reserved initialization area

0X03 设置内存开辟钩子

VisualLeakDetector::VisualLeakDetector ()

{

。。。 。。。

else if (linkdebughelplibrary()) { // 显示加载dbghelp.dll中必要的API

// Register our allocation hook function with the debug heap.

m_poldhook = _CrtSetAllocHook(allochook);

report("Visual Leak Detector Version "VLD_VERSION" installed ("VLD_LIBTYPE").\n");

reportconfig();

。。。 。。。

}

}

0x04 钩子函数

// 该函数不用考虑线程安全问题,CRT有调试堆有锁定

int VisualLeakDetector::allochook (int type, void *pdata, size_t size, int use, long request, const unsigned char *file, int line)

{

static bool inallochook = false;

int         status = true;

// 1. 防止递归;2.不处理CRT内部使用的内存块

if (inallochook || (use == _CRT_BLOCK)) {

if (visualleakdetector.m_poldhook) {

status = visualleakdetector.m_poldhook(type, pdata, size, use, request, file, line);

}

return status;

}

inallochook = true;

// Call the appropriate handler for the type of operation.

switch (type) {

case _HOOK_ALLOC:

visualleakdetector.hookmalloc(request);

break;

case _HOOK_FREE:

visualleakdetector.hookfree(pdata);

break;

case _HOOK_REALLOC:

visualleakdetector.hookrealloc(pdata, request);

break;

default:

visualleakdetector.report("WARNING: Visual Leak Detector: in allochook(): Unhandled allocation type (%d).\n", type);

break;

}

if (visualleakdetector.m_poldhook) {

status = visualleakdetector.m_poldhook(type, pdata, size, use, request, file, line);

}

inallochook = false;

return status;

}

0X05 栈回溯

#if defined(_M_IX86) || defined(_M_X64)

#pragma auto_inline(off)

DWORD_PTR VisualLeakDetector::getprogramcounterx86x64 ()

{

DWORD_PTR programcounter;

// Get the return address out of the current stack frame

__asm mov AXREG, [BPREG + SIZEOFPTR]

// Put the return address into the variable we'll return

__asm mov [programcounter], AXREG

return programcounter;

}

#pragma auto_inline(on)

#endif // defined(_M_IX86) || defined(_M_X64)

void VisualLeakDetector::getstacktrace (CallStack *callstack)

{

DWORD        architecture;

CONTEXT      context;

unsigned int count = 0;

STACKFRAME64 frame;

DWORD_PTR    framepointer;

DWORD_PTR    programcounter;

// Get the required values for initialization of the STACKFRAME64 structure

// to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame.

#if defined(_M_IX86) || defined(_M_X64)

architecture = X86X64ARCHITECTURE;

programcounter = getprogramcounterx86x64();

__asm mov [framepointer], BPREG // Get the frame pointer (aka base pointer)

#else

// If you want to retarget Visual Leak Detector to another processor

// architecture then you'll need to provide architecture-specific code to

// retrieve the current frame pointer and program counter in order to initialize

// the STACKFRAME64 structure below.

#error "Visual Leak Detector is not supported on this architecture."

#endif // defined(_M_IX86) || defined(_M_X64)

// Initialize the STACKFRAME64 structure.

memset(&frame, 0x0, sizeof(frame));

frame.AddrPC.Offset    = programcounter;

frame.AddrPC.Mode      = AddrModeFlat;

frame.AddrFrame.Offset = framepointer;

frame.AddrFrame.Mode   = AddrModeFlat;

// Walk the stack.

while (count < _VLD_maxtraceframes) {

count++;

if (!pStackWalk64(architecture, m_process, m_thread, &frame, &context,

NULL, pSymFunctionTableAccess64, pSymGetModuleBase64, NULL)) {

// Couldn't trace back through any more frames.

break;

}

if (frame.AddrFrame.Offset == 0) {

// End of stack.

break;

}

// Push this frame's program counter onto the provided CallStack.

callstack->push_back((DWORD_PTR)frame.AddrPC.Offset);

}

}

StackWalk64进行栈回溯需要精确的知道栈从哪里开始。这需要提供当前的栈帧地址和当前的EIP(RIP)寄存器值,而通过GetThreadContext获取的当前线程上下文对于一个正在运行的线程是不可靠的。所以这里通过了内联汇编代码实现,即getprogramcounterx86x64()函数的作用,其返回函数的返回地址,当函数返回时即当前的EIP(RIP)寄存器值。

内存泄漏工具VLD1.0_要点分析的更多相关文章

  1. VS2015 定位内存泄漏工具vld

    介绍一款在vs2015开发环境定位内存泄漏工具:Visual Leak Detector ,具体的使用方法如下: 1.  安装vld-2.5-setup.exe (下载链接地址后面会给出),安装过程会 ...

  2. 【腾讯优测干货分享】Android内存泄漏的简单检查与分析方法

    本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d14047603a5bf1242ad01b 导语 内存泄漏问题大约是An ...

  3. Linux下内存泄漏工具【转】

    转自:http://www.cnblogs.com/guochaoxxl/p/6970090.html 概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况 ...

  4. Linux下内存泄漏工具

    概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...

  5. js的内存泄漏场景、监控以及分析

    内存泄漏 Q:什么是内存泄漏? 字面上的意思,申请的内存没有及时回收掉,被泄漏了 Q:为什么会发生内存泄漏? 虽然前端有垃圾回收机制,但当某块无用的内存,却无法被垃圾回收机制认为是垃圾时,也就发生内存 ...

  6. Valgrind 内存泄漏工具

    Valgrind 是一款 Linux下(支持 x86.x86_64和ppc32)程序的内存调试工具,它可以对编译后的二进制程序进行内存使用监测(C语言中的malloc和free,以及C++中的new和 ...

  7. malloc钩子和内存泄漏工具mtrace、Valgrind

    一:malloc钩子函数 static void* (* old_malloc_hook) (size_t,const void *);static void (* old_free_hook)(vo ...

  8. 安卓 内存 泄漏 工具 LeakCanary 使用

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com LeakCanary是Square开源了一个内存泄露自动探测神器 .这是项目的github仓库地 ...

  9. Logcat中报内存泄漏MemoryLeak的一次分析

    有时候运行APP的时候Logcat中会报错,提示资源没有释放,Memory leak, 于是打开Android Studio在Android Monitor工具栏点开,有Logcat和Monitors ...

随机推荐

  1. Oracle官方版Entity Framework

    千呼萬喚始出來! Oracle官方版Entity Framework問市,邁入開發新時代 自從我得了一種"不用LINQ就不會寫資料庫程式"的病,為了滿足工作上要搭配Oracle(雖 ...

  2. IOS--工作总结--post上传文件(以流的方式上传)

    1.添加协议 <NSURLConnectionDelegate> 2.创建 @property (nonatomic,retain) NSURLConnection* aSynConnec ...

  3. 类 的继承性(Inherits)与 重写(Overrides)

    (类) 与 (结构) 类似,让我们可以定义并封装成一组相关项的数据类型.比如封装成结构,那么这个封装包的数据类型就为值类型:如封装成类,那么这个封装包的数据类型就为引用类型. 然而与结构的一个重要区别 ...

  4. (原+转)ROC曲线

    转自:http://baike.baidu.com/link?url=_H9luL0R0BSz8Lz7aY1Q_hew3JF1w-Zj_a51ggHFB_VYQljACH01pSU_VJtSGrGJO ...

  5. android 手势滑动

    1.概述, 两次都是画曲线统计图用到手势滑动.左滑动,右滑动曲线图翻页 2.直接上代码 3.注: 第一次使用的时候是implement了 OnTouchListener 接口,是在画图布局上layou ...

  6. 对话 UNIX: 关于 inode

    http://www.ibm.com/developerworks/cn/aix/library/au-speakingunix14/ WMI http://wiki.hudson-ci.org/di ...

  7. LoggingApplicationListener

    org.springframework.boot:spring-boot:1.3.0.M1 spring-boot-1.3.0.M1.jar package org.springframework.b ...

  8. 20个Linux命令及Linux终端的趣事

    20个Linux命令及Linux终端的趣事 . 命令:sl (蒸汽机车) 你可能了解 ‘ls’ 命令,并经常使用它来查看文件夹的内容.但是,有些时候你可能会拼写成 ‘sl’ ,这时我们应该如何获得一些 ...

  9. php信用卡卡号验证函数

    介绍一个php信用卡卡号验证函数,可以验证一个卡号是否是信用卡. function validateCard ($cardnumber){ $cardnumber = preg_replace (&q ...

  10. C++数据结构之最小生成树

    最小生成树是图的一部分,一般求最小生成树用Prim算法和Kruskal算法. 对于Prim算法,思想是:在访问过的顶点和未访问的顶点之间选择权值最小的边.Prim算法是基于顶点的操作,适合于顶点较少, ...