控制代碼洩露問題追蹤

2021-10-13 02:57:55 字數 4330 閱讀 2822

無論是在編寫windows程式還是linux程式,都可能存在控制代碼洩露的問題。在linux中一般來說乙個程序的fd使用是有上限的,可以使用ulimit命令進行上限檢視,當出現fd洩露的時候,可能會出現socket建立失敗,檔案打不開等問題。windows類似,本文主要闡述了對windows中的控制代碼洩露的追蹤方法。

在windows開發中,當呼叫windows api,比如createfile,createevent,createthread等api的時候,都會返回乙個控制代碼handle。當相應的資源使用完後,如果沒有呼叫closehandle去關閉handle,則會出現控制代碼洩露的問題。當這個問題發生的時候,當前程序再呼叫比如createthread會返回windows error1450, 表示insufficient system resources exist to complete the requested service.,導致程式執行問題。windows的總控制代碼數,也是有限制的,此時甚至會影響其他程序的執行。那麼接下來讓我們來看看如何定位控制代碼洩露問題吧。

在任務管理器中可以檢視乙個程序的控制代碼數量,在process explorer中也可以。我們可以這樣去定位控制代碼洩露問題:

可以在process explorer中顯示handles一列,如果程序有控制代碼洩露問題,那麼這個程序的handles一列的數值會持續的增長

選中相應的程序,可以觀察本程序的控制代碼詳細資訊。比如這個控制代碼,關聯的是執行緒、檔案、event等等。

當出現控制代碼洩露的時候,那麼會有大量的相似的型別的控制代碼出現在其中。

如果因為createthread的控制代碼沒有釋放,導致控制代碼洩露,那麼則可以在控制代碼詳細資訊的條目中看到很多thread型別的。然後查詢可能呼叫createthread的**。

如果因為createfile的控制代碼沒有釋放,則可以在process explorer中檢視檔案的路徑,根據檔案的路徑來查詢可能引起控制代碼洩露的**。

這種方式可以解決一部分控制代碼洩露問題,但是有時候可能碰到一些場景不能解決:

乙個產品可能依賴於多個第三方模組,當控制代碼洩露的問題是第三方模組引起的,可能看到洩露控制代碼型別和名字也難以定位到具體的模組。

process explorer不能夠顯示所有的控制代碼,比如無名的event,這樣也無法查詢。

除了上一章末講的兩個問題,那麼有沒有一種方法可以定位到這個洩露的控制代碼申請的地方嗎?windbg就可以做到。

先上一段測試的sample, 每隔一秒鐘建立乙個event,但並沒有呼叫closehandle, 會導致handle leak。

#include #include #include void handleleak()	}}

int main()

第一步用windbg attach到你要測試程序

第二步windbg中呼叫命令!htrace -enable: 開啟控制代碼追蹤,並且儲存當前所有的handle的快照(snapshot)

0:006> !htrace -enable

handle tracing enabled.

handle tracing information snapshot successfully taken.

第三步windobg中呼叫命令g, 讓程式執行一段時間

第四步選單debug->break進入除錯,windbg中執行!htrace -diff: 將程序當前的所有的控制代碼和之前快照的控制代碼進行對比,找出這段時間內多出來的控制代碼。

0:006> !htrace -diff

handle tracing information snapshot successfully taken.

0x31 new stack traces since the previous snapshot.

ignoring handles that were already closed...

outstanding handles opened since the previous snapshot:

--------------------------------------

handle = 0x0000000000000290 - open

thread id = 0x0000000000001ca0, process id = 0x0000000000004360

0x00007ffca4dcb2a4: ntdll!ntcreateevent+0x0000000000000014

0x00007ffca1ebb623: kernelbase!createeventa+0x0000000000000083

0x00007ff7ea001e94: handleleak!handleleak+0x0000000000000034

0x00007ff7ea002099: handleleak!main+0x0000000000000009

0x00007ff7ea0023d4: handleleak!__scrt_common_main_seh+0x000000000000010c

0x00007ffca23f4034: kernel32!basethreadinitthunk+0x0000000000000014

0x00007ffca4da3691: ntdll!rtluserthreadstart+0x0000000000000021

--------------------------------------

handle = 0x0000000000000280 - open

thread id = 0x0000000000001ca0, process id = 0x0000000000004360

0x00007ffca4dcb2a4: ntdll!ntcreateevent+0x0000000000000014

0x00007ffca1ebb623: kernelbase!createeventa+0x0000000000000083

0x00007ff7ea001e94: handleleak!handleleak+0x0000000000000034

0x00007ff7ea002099: handleleak!main+0x0000000000000009

0x00007ff7ea0023d4: handleleak!__scrt_common_main_seh+0x000000000000010c

0x00007ffca23f4034: kernel32!basethreadinitthunk+0x0000000000000014

0x00007ffca4da3691: ntdll!rtluserthreadstart+0x0000000000000021

第五步通過上述的handle呼叫棧,就很容易能夠知道導致控制代碼洩露的**了。

以上方法可以比較完美的解決控制代碼洩露問題,但是如果問題本地難以重現,需要到客戶環境中查詢控制代碼洩露問題,那麼一般不太建議symbols拷貝到客戶的環境中,以免造成symbols洩露。那麼上述第四步中就無法檢視到明確的函式呼叫棧,可以從客戶環境中拷貝出來第四步!htrace -diff的資訊,然後再自己本地load symbols後通過ln handleleak+0x....檢視相應的函式呼叫棧,從而定位問題。

除了以上方法,還有一些可以在windbg中直接檢視handle的方式來查詢控制代碼洩露:

通過!handle命令檢視當前程序的所有控制代碼

通過對比兩個時間點的!handle命令的結果,找出控制代碼洩露的型別

找出兩個時間點差異化的控制代碼的索引,再使用!handle f檢視控制代碼的詳細資訊。

通過洩露的控制代碼的型別,詳細資訊(比如名稱)來輔助定位可能的控制代碼洩露位置

linux控制代碼洩露問題檢視

檢視與修改控制代碼 在linux系統中可以通過ulimit n檢視每個程序限制的最大控制代碼數,通過ulimit hsn 10240修改程序的最大控制代碼數。當控制代碼數目達到限制後,就回出現 too many files open 檢視程序占用的控制代碼數有幾種辦法 1 通過cat proc pi...

控制代碼洩露除錯

控制代碼洩露除錯 控制代碼洩露除錯 handles leak debug 一 概述 造成控制代碼洩露的主要原因,是程序在呼叫系統檔案之後,沒有釋放已經開啟的檔案控制代碼。對於控制代碼洩露,輕則影響某個功能模組正常執行,重則導致整個應用程式崩潰。在 windows系統中,gdi 控制代碼上限是 120...

windbg除錯 控制代碼洩露

1 用c 寫乙個控制代碼洩露的樣例程式 include stdafx.h include void fun1 void void fun2 void void fun3 void void fun4 void int main int argc,char argv return 0 void fun...