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

来源:https://www.cnblogs.com/z16166/archive/2022/12/04/16950296.html
-Advertisement-
Play Games

說明: 1. 本文基於Spring-Framework 5.1.x版本講解 2. 建議讀者對Mybatis有基本的使用經驗 概述 這一篇我們講講org.springframework.beans.factory.FactoryBean介面,這個介面功能非常強大,可以集成不同的中間件或組件到Sprin ...


讓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的符號庫函數。

__declspec(dllexport) VisualLeakDetector g_vld;

在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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Nginx (Engine X)是一個輕量級的Web伺服器 、反向代理伺服器及電子郵件(IMAP/POP3)代理伺服器、高性能的HTTP伺服器,它以高穩定性、豐富的功能集、示例配置文件和低系統資源的消耗而聞名。 ...
  • 如果你接手了別人的代碼工程,卻發現對方使用的 python 版本或者依賴庫都和你的環境不相容時,怎麼辦?打算卸掉自己原來的那一套環境再重來嗎?真麻煩! ...
  • 該筆記整理至尚矽谷周陽老師的SpringCloud課程SpringCloud Alibaba篇 SpringCloud Alibaba入門簡介 Spring Cloud Netflix 項目進入維護模式,Spring Cloud Netflix 將不再開發新的組件。Spring Cloud 版本迭代 ...
  • ###Http Http (超文本輸出協議) 是一種分散式、協作式和超媒體信息系統的應用層協議,它通常運行在TCP之上,網際網路應用最廣泛的便是Http協議,所有www都遵循這個標準。主要用於Web 瀏覽器與 Web 伺服器之間的通信而設計的,但也可以用於其他目的,是一個基於 TCP/IP 通信協議來 ...
  • 隨著跨境獨立站的流行,中英雙語的公司官網越來越受到重視。 此項目是基於開源CMS開發出的中英文雙語外貿企業網站內容管理系統,命名HanCMS HanCMS 漢CMS中英雙語多語種外貿網站系統,是一個輕量級的網站系統,訪問速度極快,使用簡單。程式代碼簡潔嚴謹,完全免費開源。可用於建設各種類型的中英文網 ...
  • 原文: JDK中內嵌JS引擎介紹及使用 - Stars-One的雜貨小窩 最近研究閱讀這個APP,其主要功能就是通過一個個書源,從而實現移動端閱讀的體驗 比如說某些線上小說閱讀網站,會加上相應的廣告,從而影響用戶閱讀體驗,於是閱讀這個APP就是做了類似凈化閱讀體驗 但是小說閱讀網站千千萬萬,如果去適 ...
  • 概述 ZYNQ分為PS和PL兩部分,PS端即ARM,PL即FPGA。在使用ZYNQ的時候不免需要PS和PL端進行通信。大多是情況下PS作為主端,PL作為從端,通過AXI匯流排實現PS-PL端的通信。本文主要介紹PL(即FPGA)如何配置的。 Block Design創建 1.點擊Create Bloc ...
  • 動態代理和責任鏈設計模式適用範圍廣,在Spring和MyBatis有著重要的應用,比如SpringAOP、Mybatis的插件技術,想要搞懂當中的技術原理必須掌握上面兩個設計模式。 代理模式可以理解為您要操作一個對象,但是要經過這個對象的“代理”對象去操作。就好似你在一家軟體公司做開發,客戶發現程式 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...