首页IT科技visual recoil(让Visual Leak Detector使用最新10.0版本的dbghelp.dll)

visual recoil(让Visual Leak Detector使用最新10.0版本的dbghelp.dll)

时间2025-09-19 11:23:33分类IT科技浏览6439
导读:让Visual Leak Detector使用最新10.0版本的dbghelp.dll 介绍...

让Visual Leak Detector使用最新10.0版本的dbghelp.dll

介绍

VLD(Visual Leak Detector)是一个检测Windows C++程序内存泄漏的老牌神器                  ,但好几年没维护了                  。

网址:https://github.com/KindDragon/vld/

需求

这个工具通过SxS manifest绑定了只能使用它工程目录下自带的dbghelp.dll来处理pdb符号                           ,版本是6.11.1.404                           。

这个版本目前比较老了         ,所以在解析VS2019/VS2022生成的pdb文件时                  ,有时候会崩掉或者无法解析出调用栈的符号                           ,导致无法报出来完整的内存泄漏         ,影响基本功能         。所以需要升级它所使用的dbghelp.dll                  。

VLD的实现机制

在首次进入vld_x64.dll的PE入口时         ,inline hook掉ntdll.dll的LdrpCallInitRoutine()函数                           ,因为此时可以假定vld_x64.dll是被ntdll.dll的LdrpCallInitRoutine()函数调用的                           。

这样后续ntdll.dll调用当前进程中的任何dll的入口函数时                  ,都会先调用vld_x64.dll提供的一个LdrpCallInitRoutine() hook函数         。

完成hook后         ,会执行vld_x64.dll中的各个全局对象的构造         。vld_x64.dll提供了一个全局对象g_vld                           ,这个对象的构造函数会调用dbghelp.dll的SymInitializeW()来初始化MS的符号库函数                           。

在LdrpCallInitRoutine() hook函数中                  ,VLD会刷新当前进程所加载的模块列表,调用dbghelp.dll的SymLoadModuleExW()加载新dll的pdb符号                  。

BOOLEAN WINAPI LdrpCallInitRoutine(IN PVOID BaseAddress, IN ULONG Reason, IN PVOID Context, IN PDLL_INIT_ROUTINE EntryPoint) { LoaderLock ll; if (Reason == DLL_PROCESS_ATTACH) { g_vld.RefreshModules(); } return EntryPoint(BaseAddress, Reason, (PCONTEXT)Context); }

问题

这样看起来并无问题         。但是10.0版本的dbghelp.dll相比6.11版本有一个改动                           ,导致VLD现有的pdb符号解析功能失败                           。

那就是10.0版本的SymInitializeW()的内部代码会去加载某些DLL                           ,这会导致走到LdrpCallInitRoutine() hook函数中去刷新模块列表,并最终调用SymLoadModuleExW()                  。

也就是说SymInitializeW()在成功返回之前会去调用SymLoadModuleExW()                  ,这显然不符合MS的debug help API的约定                           ,所以此时的SymLoadModuleExW()都会返回失败         ,导致汇报泄漏时无法解析符号。

解决办法

1                  、设置一个全局的bool标志变量                  ,在调用SymInitializeW()之前置位                           ,调用完SymInitializeW()之后清除                           。

dbghelp.h:
extern volatile bool init; BOOL SymInitializeW(_In_ HANDLE hProcess, _In_opt_ PCWSTR UserSearchPath, _In_ BOOL fInvadeProcess) { init = true; CriticalSectionLocker<CriticalSection> cs(m_lock); const auto r = ::SymInitializeW(hProcess, UserSearchPath, fInvadeProcess); init = false; return r; }

2                           、在LdrpCallInitRoutine() hook函数中判断一下         ,如果标志被置位         ,则本次就不要刷新模块列表了                           ,也就不会去调用SymLoadModuleExW()                           。

vld.cpp:
volatile bool init = false; BOOLEAN WINAPI LdrpCallInitRoutine(IN PVOID BaseAddress, IN ULONG Reason, IN PVOID Context, IN PDLL_INIT_ROUTINE EntryPoint) { LoaderLock ll; if (Reason == DLL_PROCESS_ATTACH) { if (!init) g_vld.RefreshModules(); } return EntryPoint(BaseAddress, Reason, (PCONTEXT)Context); }

3         、相应地                  ,要删掉VLD工程属性中添加的和SxS有关的设置         ,如

vld.dll.dependency.x64.manifest vld.dll.dependency.x86.manifest dbghelp.dll (6.11版本的) Microsoft.DTfW.DHL.manifest (6.11版本的) $(SolutionDir)\lib\dbghelp\lib\$(PlatformName) (不要依赖这个目录下的lib)

这样编译出来的vld_x64.dll默认会加载system32下的dbghelp.dll。

也可以复制Windows SDK                  、VS2019/VS2022                           、windbg目录下的dbghelp.dll                           ,但不要忘了也复制同目录下的那一堆api-ms-win-crt-runtime-l1-1-0.dll之类的CRT dll                  。

附赠

几个防止内存泄漏的tips:

1         、静态链接到openssl时                  ,需要在DLL_THREAD_DETACH时调用OPENSSL_thread_stop()释放PTD(即per-thread-data)                           。

2         、静态链接到log4cplus时,需要在DLL_THREAD_DETACH时调用log4cplus::threadCleanup()释放per-thread-data         。

3                           、libzip有两个坑(其文档写得不甚清楚):

一                  、zip_close()会顺带将关联的zip source的句柄也关闭                           ,所以对应的zip source句柄不要再单独关闭                  。

如果要保留zip source句柄另作他用                           ,需要在zip_close()之前先用zip_source_keep()将zip source的句柄引用计数加1                           。

二         、zip source句柄用zip_source_free()释放,而不是用zip_source_close()         。

zip_source_free()还有限制                  ,参看其文档         。

参考:

https://github.com/KindDragon/vld/issues/86
声明:本站所有文章                           ,如无特殊说明或标注         ,均为本站原创发布                           。任何个人或组织                  ,在未征得本站同意时                           ,禁止复制                           、盗用                  、采集、发布本站内容到任何网站                           、书籍等各类媒体平台                  。如若本站内容侵犯了原著者的合法权益         ,可联系我们进行处理         。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
windows如何卸载kb5000908(Win10 KB5004945怎么卸载? 删除KB5004945的两种方法)