青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

來吧,朋友!

為C++瘋狂

通往WinDbg的捷徑(一)

[轉載]通往WinDbg的捷徑(一)

原文:http://www.debuginfo.com/articles/easywindbg.html
譯者:arhat
時間:2006年4月13日
關鍵詞:CDB WinDbg 

導言
你鐘情什么樣的調試器?如果你問我這個問題,我會回答是“Visual Studio + WinDbg”。我比較喜歡Visual Studio那樸實無華且易操作的接口,更喜歡它能迅速把我需要的信息以可視的形式展示出來。但遺憾的是,Visual Studio調試器無法獲取某些信息。例如,假設我想知道哪個線程正在占用特殊的臨界區?或者是哪個函數占用了大部分的??臻g?不用擔心,有WinDbg呢。它的命令能回答這些問題,以及調試過程中出現的其它有趣的問題。甚至不退出Visual Studio,WinDbg就可以附上目標應用程序??謝謝WinDbg支持入侵模式的調試(本文后面會詳細討論),我們可以把Visual Studio GUI和WinDbg的命令行結合起來使用。
唯一的問題是WinDbg不太好用。需要花些時間適應它的用戶界面,而掌握它的命令則要花更多的時間。但是假設你現在就需要它,馬上用它調試緊急的問題?有什么快速簡便的方法嗎?當然。WinDbg的小弟CDB,功能和WinDbg差不多;因為它是基于命令行的,所以用起來更簡單一些。在這篇文章里,我將把CDB作為Visual Studio調試器的補充,介紹怎樣使用CDB。在這篇文章里,你將會看到怎樣配置CDB,怎樣用它解決實際的問題。另外,我還會提供一些批處理文件,它們可以隱藏CDB命令行接口的大部分復雜性,也讓你少打幾個字。

安裝與配置
安裝

當然,在使用CDB前,必須先安裝并配置它。WinDbg和CDB是Debugging Tools for Windows 的一部分,可以從這里下載。安裝很簡單,你可以用默認設置安裝,除非你準備用WinDbg SDK開發應用程序。(如果你準備用SDK,需要選擇定制安裝,并啟用SDK安裝;推薦你把它安裝在不包含空格的目錄名的目錄中)。安裝完成后,安裝目錄里將包含所有必需的文件,包括WinDbg(windbg.exe)和CDB(cdb.exe)。
調試工具也支持“xcopy”類型的安裝。也就是說,在一臺機器上安裝后,如果你想在其它的機器上使用,不用再安裝,直接把已經安裝的目錄直接拷過去就行了。

符號文件服務器路徑 
如果不能訪問操作系統DLL的最新的符號文件,有些重要的WinDbg命令將不能正常工作。在以往,我們可以從微軟的FTP服務器上下載巨大的符號文件包,然后從中找出需要的符號文件。這非常浪費時間,而且在操作系統更新或升級后,符號文件就過時了(因此也就變得毫無用處)。幸運的是,現在有更簡便的方法來獲得符號文件??符號文件服務器。WinDbg和Visual Studio都支持這個方法,在需要時直接從微軟維護的服務上下載最新的符號文件。有了符號文件服務器,我們再也不用下載整個符號文件包了(那實在是太大了),因為調試器知道需要用到哪個DLLs,所以直接下載單個符號文件就行了。如果符號文件在操作系統更新或升級以后過時了,調試器會注意到這種情形,并再次下載必需的符號文件。
為了使符號文件服務器起作用,我們應該讓調試器知道符號文件服務器的路徑。最簡單的方法是在_NT_SYMBOL_PATH環境變量里指定符號文件服務器的路徑??梢杂萌缦碌穆窂剑?br _fckxhtmljob="6">"srv*c:\symbolcache*http://msdl.microsoft.com/download/symbols" 
(c:\symbolcache目錄將被用來保存從符號文件服務器下載下來的符號文件;當然,你可以用任何有效的本地或網絡路徑)。例如:
  set _NT_SYMBOL_PATH=srv*c:\symbols*http://msdl.microsoft.com/download/symbols
在你設置_NT_SYMBOL_PATH環境變量之后,就可以使用符號文件服務器了。關于符號文件服務器的更多信息,相關設置,以及可能會用到的排除故障的小技巧,可以從WinDbg的文檔中找到(Debuggers | Symbols section)。
如果你需要從一臺需登錄的代理服務器后訪問符號文件服務器。參見本篇文章中CDB and proxy servers部分,以了解更多信息。

CDB 命令行基礎介紹 
啟動調試會話

當我們使用新的調試器時,第一個問題通常是:怎樣開始調試會話呢?像大多數調試器一樣,CDB允許我們調試應用程序的新實例,或者附上一個已經運行的過程。啟動新實例就象下面一樣簡單:
  cdb c:\myapp.exe
如果我們想附上已經運行的過程,可能會用上下列某個選項:
----------------------------------------------------------------------------------------------------------------------
選項                描述                                                                            例子
----------------------------------------------------------------------------------------------------------------------
-p Pid              這個選項允許CDB附上指定進程ID的進程??梢杂萌蝿展芾砥骰蝾愃频墓ぞ叩玫竭M程ID。   cdb -p 1034
----------------------------------------------------------------------------------------------------------------------
-pn ExeName         這個選項允許CDB用指定的可執行文件名(.exe)附上進程。這個選項比“-p Pid”更
                    方便,因為我們通常知道執行的程序名,不必在任務管理器中尋找進程的ID。但是如果
                    多個進程使用同一個名字(CDB將報錯),就不能用這個選項了。                       cdb -pn myapp.exe
----------------------------------------------------------------------------------------------------------------------
-psn ServiceName    這個選項允許CDB附上指定服務的進程。例如,假如你想附上Windows Management 
                    Instrumentation服務,應該用WinMgmt作為服務名。                                  cdb -psn MyService
----------------------------------------------------------------------------------------------------------------------

CDB也可以分析故障轉儲。用-z選項打開故障轉儲:
  cdb -z DumpFile
例如:
  cdb -z c:\myapp.dmp

結束調試會話 
啟動新的調試會話后,CDB會顯示它自己的命令行提示符。你可以在這個提示符下執行CDB支持的任何命令。
http://www.debuginfo.com/articles/pic/cdbconsole.jpg  
'q'命令結束調試會話并退出CDB:
0:000> q
quit:
>
警告:當你結束調試會話,退出CDB時,操作系統也將終止被調試的程序。如果你想退出CDB并保持被調試程序,可以用.detach命令(Windows XP或更新的操作系統才支持),或者用非入侵的模式(下面討論)。

運行命令 
雖然可以在CDB命令行提示符下執行調試器命令,但在命令行里指定需要的命令通常更快一些,用-c選項。
  cdb -pn myapp.exe -c "command1;command2"
(用分號分隔多個命令)
例如,下列命令行將把CDB附上我們的應用程序,顯示已加載的模塊,然后退出:
  cdb -pn myapp.exe -c "lm;q"
注意,在命令列表的結尾加上'q'命令??將在所有的調試器命令執行后關閉CDB。

入侵模式調試
在默認情況下,當我們用CDB調試一個已經運行的進程時,它通常作為全功能的調試器附上進程(使用Win32 Debugging API)。在這種模式下,可以設置斷點,單步調試代碼,得到各種調試事件的通知(例如,異常,加載/卸載模塊,啟動/退出線程,等等)。Visual Studio也可以做到這些,并提供更友好的用戶界面。另外,每個進程每次只能被一個調試器附上。這是否意味著如果我們用Visual Studio調試器調試應用程序,就不能再用CDB得到它的附加信息了?不,不完全是這樣,因為除了全功能調試模式外,CDB還支持入侵調試模式。
CDB以入侵模式附上目標進程時,并沒有使用Win32 Debugging API,而是先暫停目標進程的所有線程,執行用戶指定的命令。在所有的命令執行之后,CDB退出之前,恢復暫停的線程。因此,目標進程可以繼續運行,好像什么事也沒發生一樣。即使像Visual Studio之類的全功能調試器正在調試目標進程,CDB仍可以用入侵模式附上它,并獲得所需要的信息。在CDB完成任務并分離附上的進程后,我們可以繼續用Visual Studio調試器調試這個應用程序。
怎么啟用CDB的入侵模式?用-pv命令行選項。例如,下列命令行將以入侵模式附上應用程序,顯示已加載模塊的列表,然后退出。在CDB退出之后,應用程序將繼續運行。
  cdb -pv -pn myapp.exe -c "lm;q"

把輸出內容保存到日志文件 
有些CDB命令的輸出內容可能會很長,從控制臺窗口閱讀十分不便。因此,把輸出內容保存到日志文件,再用其它的編輯器查看會更好一些,CDB允許我們用-loga和-logo選項來實現('-loga <filename>'把輸出內容追加到指定文件的結尾;而'-logo <filename>'將覆蓋原有的文件,如果文件已經存在的話)。
在我們的例子命令(列出目標進程里的模塊)里增加記錄功能,把輸出內容保存到當前目錄的out.txt文件里:
  cdb -pv -pn myapp.exe -logo out.txt -c "lm;q"

源行號信息 
CDB支持的另外一個重要選項是-lines。這個選項打開源行號信息支持,例如,當報告調用棧時,允許CDB顯示源文件及源行號。(在默認情況下,源行號支持是關閉的,CDB不顯示源文件/行號信息)。

CDB 和代理服務器 
如果你在需要登錄的代理服務器后用CDB,在默認情況下,將不能訪問符號文件服務器。原因是在默認配置下,當CDB嘗試連接符號文件服務器時,不顯示代理服務器的登錄提示。為了更改這個行為,使我們可以訪問符號文件服務器,需要在命令行之前加上兩條命令:
  !sym prompts;.reload
例如:
  cdb -pv -pn myapp.exe -logo out.txt -c "!sym prompts;.reload;lm;q"

啟動消息
當CDB調試新應用程序,附上已經存在的進程,或打開故障轉儲時,將顯示一系列的啟動消息。CBD命令(可以用-c選項指定,或手動輸入)的輸出內容跟在這些消息之后。通常情況下,啟動消息只顯示一些無關緊要信息;但是如果在執行時出錯了,它將包含這個問題的描述,有時候也會提供解決方法。
例如,下列輸出內容通知我們沒有設置符號路徑,因此,有些調試器命令不能工作:
D:\Progs\DbgTools>cdb myapp.exe

Microsoft (R) Windows Debugger  Version 6.5.0003.7
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: myapp.exe
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path.           *
* Use .symfix to have the debugger choose a symbol path.                   *
* After setting your symbol path, use .reload to refresh symbol locations. *
****************************************************************************

總結
這里是一些常見的CDB命令行模板,本篇文章的剩下部分將會用到它們(我們總是用同樣的模板,然后根據我們要解決的問題,改變-c選項內部的命令行列表)。
用入侵模式附上運行的進程(通常是進程ID),執行一組命令,并把輸出內容保存在out.txt文件里:
  cdb -pv -p <processid> -logo out.txt -lines -c "command1;command2;...;commandN;q"
用入侵模式附上運行的進程(用可執行文件名),執行一組命令,并把輸出內容保存在out.txt文件里:
  cdb -pv -pn <exename> -logo out.txt -lines -c "command1;command2;...;commandN;q"
用入侵模式附上運行的進程(通常是服務名),執行一組命令,并把輸出內容保存在out.txt文件里:
  cdb -pv -psn <servicename> -logo out.txt -lines -c "command1;command2;...;commandN;q"
打開故障轉儲文件,執行一組命令,并把輸出內容保存在out.txt文件里:
  cdb -z <dumpfile> -logo out.txt -lines -c "command1;command2;...;commandN;q"
如果我們在需要登錄的代理服務器后使用CDB,要訪問符號文件服務器,需要增加兩條命令。例如:
  cdb -pv -pn <exename> -logo out.txt -lines -c "!sym prompts;.reload;command1;command2;...;commandN;q"
好像要打好多字?其實不是這樣,稍后,我將提供一些批處理文件,它們將為我們隱藏重復的命令行選項,把要我們輸入的內容減至最小。

解決實際的問題
調試死鎖問題

當我們的應用程序掛起或停止響應時,最自然的問題是:它現在正在做什么?它在哪里被困住了?當然,我們可以用Visual Studio調試器附上應用程序,檢查所有線程的調用棧。但我們同樣可以用CDB,而且會更快一些。下列命令將使CDB以入侵模式附上應用程序,打印所有的調用棧,把結果保存在日志文件里,然后退出:
  cdb -pv -pn myapp.exe -logo out.txt -lines -c "~*kb;q"
('kb'命令要求CDB打印當前線程的調用棧;'~*'前綴要求CDB在進程所有已存在的線程里重復執行'kb'命令)。
[/URL] DeadLockDemo.cpp是一個演示典型的死鎖問題的例子。如果你編譯并運行,它的工作線程馬上會被困住,如果我們運行上述的命令來查看應用程序的線程正在做什么,將看到下列類似的內容(在這,以及后面,我們將省略啟動消息):
.  0  Id: 6fc.4fc Suspend: 1 Teb: 7ffdf000 Unfrozen
ChildEBP RetAddr  Args to Child              
0012fdf8 7c90d85c 7c8023ed 00000000 0012fe2c ntdll!KiFastSystemCallRet
0012fdfc 7c8023ed 00000000 0012fe2c 0012ff54 ntdll!NtDelayExecution+0xc
0012fe54 7c802451 0036ee80 00000000 0012ff54 kernel32!SleepEx+0x61
0012fe64 004308a9 0036ee80 a0f63080 01c63442 kernel32!Sleep+0xf
0012ff54 00432342 00000001 003336e8 003337c8 DeadLockDemo!wmain+0xd9 
  [c:\tests\deadlockdemo\deadlockdemo.cpp @ 154]
0012ffb8 004320fd 0012fff0 7c816d4f a0f63080 DeadLockDemo!__tmainCRTStartup+0x232 
  [f:\rtm\vctools\crt_bld\self_x86\crt\src\crt0.c @ 318]
0012ffc0 7c816d4f a0f63080 01c63442 7ffdd000 DeadLockDemo!wmainCRTStartup+0xd 
  [f:\rtm\vctools\crt_bld\self_x86\crt\src\crt0.c @ 187]
0012fff0 00000000 0042e5aa 00000000 78746341 kernel32!BaseProcessStart+0x23

   1  Id: 6fc.3d8 Suspend: 1 Teb: 7ffde000 Unfrozen
ChildEBP RetAddr  Args to Child              
005afc14 7c90e9c0 7c91901b 000007d4 00000000 ntdll!KiFastSystemCallRet
005afc18 7c91901b 000007d4 00000000 00000000 ntdll!ZwWaitForSingleObject+0xc
005afca0 7c90104b 004a0638 00430b7f 004a0638 ntdll!RtlpWaitForCriticalSection+0x132
005afca8 00430b7f 004a0638 005afe6c 005afe78 ntdll!RtlEnterCriticalSection+0x46
005afd8c 00430b15 005aff60 005afe78 003330a0 DeadLockDemo!CCriticalSection::Lock+0x2f 
  [c:\tests\deadlockdemo\deadlockdemo.cpp @ 62]
005afe6c 004309f1 004a0638 f3d065d5 00334fc8 DeadLockDemo!CCritSecLock::CCritSecLock+0x35 
  [c:\tests\deadlockdemo\deadlockdemo.cpp @ 90]
005aff6c 004311b1 00000000 f3d06511 00334fc8 DeadLockDemo!ThreadOne+0xa1 
  [c:\tests\deadlockdemo\deadlockdemo.cpp @ 182]
005affa8 00431122 00000000 005affec 7c80b50b DeadLockDemo!_callthreadstartex+0x51 
  [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]
005affb4 7c80b50b 003330a0 00334fc8 00330001 DeadLockDemo!_threadstartex+0xa2 
  [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 331]
005affec 00000000 00431080 003330a0 00000000 kernel32!BaseThreadStart+0x37

   2  Id: 6fc.284 Suspend: 1 Teb: 7ffdc000 Unfrozen
ChildEBP RetAddr  Args to Child              
006afc14 7c90e9c0 7c91901b 000007d8 00000000 ntdll!KiFastSystemCallRet
006afc18 7c91901b 000007d8 00000000 00000000 ntdll!ZwWaitForSingleObject+0xc
006afca0 7c90104b 004a0620 00430b7f 004a0620 ntdll!RtlpWaitForCriticalSection+0x132
006afca8 00430b7f 004a0620 006afe6c 006afe78 ntdll!RtlEnterCriticalSection+0x46
006afd8c 00430b15 006aff60 006afe78 003332e0 DeadLockDemo!CCriticalSection::Lock+0x2f 
  [c:\tests\deadlockdemo\deadlockdemo.cpp @ 62]
006afe6c 00430d11 004a0620 f3e065d5 00334fc8 DeadLockDemo!CCritSecLock::CCritSecLock+0x35 
  [c:\tests\deadlockdemo\deadlockdemo.cpp @ 90]
006aff6c 004311b1 00000000 f3e06511 00334fc8 DeadLockDemo!ThreadTwo+0xa1 
  [c:\tests\deadlockdemo\deadlockdemo.cpp @ 202]
006affa8 00431122 00000000 006affec 7c80b50b DeadLockDemo!_callthreadstartex+0x51 
  [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]
006affb4 7c80b50b 003332e0 00334fc8 00330001 DeadLockDemo!_threadstartex+0xa2 
  [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 331]
006affec 00000000 00431080 003332e0 00000000 kernel32!BaseThreadStart+0x37
調用棧(和源行號)暗示ThreadOne正在占用臨界區CritSecOne并等待臨界區CritSecTwo,然而ThreadTwo正占用臨界區CritSecTwo并等待臨界區CritSecOne。這是典型的“lock acquisition order”死鎖例子,在那里,兩個線程需要得到同一組同步的對象,以不同的順序使用。如果你想避免這種類型的死鎖,必須保證所有的線程以相同的順序得到所需的同步對象(在這個例子里,ThreadOne和ThreadTwo能同意首先得到CritSecOne,然后得到CritSecTwo來避免死鎖)。
在默認情況下,'kb'命令只顯示調用棧的前20幀。如果你想查看更多的棧幀,你可以顯式指明顯示的棧幀數量(例如,'kb100'命令要求調試器顯示100幀)。在WinDbg會話里,可以用.kframes命令改變隨后命令的默認限制。
我們的例子只包含了三個簡單的線程,很容易看出哪個線程應該為死鎖負責。在大應用程序里,很難找出可疑的線程并進行驗證。那我們應該怎么做呢?在大部分情況下,我們應該知道那個沒有正常運轉的線程(否則,我們怎么會注意到應用程序出現異常了呢?)。通常,這個線程是在等待同步對象,這個對象因為某些原因暫時不可用。這個對象為什么不可用呢?如果我們知道哪個線程正在占用這個對象(擁有它,換句話說),應該能答出這個問題。如果這個對象碰巧在臨界區,!locks命令應該能幫助我們識別出它的當前所有者。當不帶參數使用時,這條命令顯示應用程序線程正在占用的臨界區的列表。輸出的內容不包括已釋放的臨界區。
讓我看看實際使用中的!locks命令:
  cdb -pv -pn myapp.exe -logo out.txt -lines -c "!locks;q"
下面是這條命令的輸出內容(同樣以DeadLockDemo.cpp為例):
CritSec DeadLockDemo!CritSecOne+0 at 004A0620
LockCount          1
RecursionCount     1
OwningThread       3d8
EntryCount         1
ContentionCount    1
*** Locked

CritSec DeadLockDemo!CritSecTwo+0 at 004A0638
LockCount          1
RecursionCount     1
OwningThread       284
EntryCount         1
ContentionCount    1
*** Locked

仔細查看了40個臨界區
查看!locks命令的輸出(尤其是OwningThread字段),我們可以推斷出臨界區CritSecOne被ID為0x3d8的線程占用,臨界區CritSecTwo被ID為0x284的線程占用。我們可以在'kb'命令的輸出內容(在前面的輸出里)里找出這些IDs對應的線程。
如果應用程序使用其它種類的同步對象(例如,互斥),識別它們的所有者將更難一些(需要內核調試器),我準備在以后的文章中再介紹這部分內容。

調試CPU高消耗的問題 
對大多數軟件來說,太高的CPU消耗率(根據任務管理器的顯示,在單CPU上接近100%)明顯指出軟件中有bug。通常意味著應用程序的某個線程陷入了死循環。當然,調試這個問題的、最普通的方法是用Visual Studio調試器附上這個進程,查找哪個線程在搗亂。但是我們應該檢查哪個線程呢?CDB為我們提供了簡便的方法??!runaway命令。當不帶參數使用時,這條命令顯示應用程序每個線程執行用戶模式代碼時所花的時間(使用另外的參數,可以顯示在內核模式下所花的時間,自線程啟動后占用的時間等)。
如下是在CDB下使用這條命令的示例:
  cdb -pv -pn myapp.exe -logo out.txt -c "!runaway;q"
下面是!runaway命令的輸出示例:
0:000> !runaway
 User Mode Time
  Thread       Time
   1:358       0 days 0:00:47.408
   2:150       0 days 0:00:03.495
   0:d8        0 days 0:00:00.000
看起來好像是ID為0x358的線程占用了大部分的CPU時間。但這個消息還不足以證明線程0x358就是罪魁禍首,因為這條命令顯示的CPU時間是線程在它整個生命期中所花的。我們還需要進一步查看線程所用CPU時間的變化情況。讓我們再次運行這條命令。這次,我們可以看到類似于下列的內容:
0:000> !runaway
 User Mode Time
  Thread       Time
   1:358       0 days 0:00:47.408
   2:150       0 days 0:00:06.859
   0:d8        0 days 0:00:00.000
現在,我們可以把這個輸出內容與上次的輸出內容做個比較,找出CPU時間增長最快的線程。在這個例子里,很明顯就是線程0x150?,F在,我們可以用Visual Studio調試器附上這個應用程序,切換到這個線程下,檢查它為什么轉個不停。

調試棧溢出
當我們想找出棧溢出異常的原因時,CDB也非常有幫助。當然,無控制的遞歸調用是棧溢出最典型的原因,通常來說,查看損壞了的線程的調用棧,找出它從哪里脫離控制就可以了。Visual Studio在這方面可以做的很好,那為什么還要用CDB呢?讓我們設想一個更復雜的例子。例如,假設我們的應用程序中包含一個依賴遞歸的算法?我們在設計算法時使用有符號數,在所有可能的情形下控制遞歸的運行,但某個時候棧仍溢出了。為什么?或許是因為在某種情況下,算法使用的某些函數占用了太多的棧空間。我們怎么確定函數占用的總的??臻g呢?不幸地是,Visual Studio調試器沒有簡便的方法可以做到。
即使調用棧沒有顯示任何遞歸的跡象時,應用程序也可能會出現棧溢出異常。例如,查看StackOvfDemo.cpp例子。如果你編譯,并在調試器下運行它,將立刻出現棧溢出。但此刻的調用??雌饋硪磺姓#?br _fckxhtmljob="6">StackOvfDemo.exe!_woutput
StackOvfDemo.exe!wprintf
StackOvfDemo.exe!ProcessStringW
StackOvfDemo.exe!ProcessStrings
StackOvfDemo.exe!main
StackOvfDemo.exe!mainCRTStartup
KERNEL32.DLL!_BaseProcessStart@4
顯然,調用棧上的某個函數使用了太多的??臻g。但是我們怎么找出這個函數呢?不用擔心,有了CDB的'kf'命令的幫助,可以顯示每個函數在調用棧上占用的字節數。在應用程序還停在Visual Studio調試器里的時候,我們可以運行下列命令:
  cdb -pv -pn stackovfdemo.exe -logo out.txt -c "~*kf;q"
('kf'默認顯示調用棧上最后的20幀,像我們在“調試死鎖問題”部分討論的那樣。如果你想多顯示一些,可以增加前綴,例如,~*kf1000。另外要注意的是,~*kf將報告所有線程的調用棧。如果應用包含大量的線程,它就不太適合了,這時,可以把它改成'~~[tid]kf', 'tid'是目標線程的線程ID(例如,'~~[0x3a8]kf'))
這條命令顯示的內容如下:
.  0  Id: 210.3a8 Suspend: 1 Teb: 7ffde000 Unfrozen
  Memory  ChildEBP RetAddr  
          00033440 0041aca5 StackOvfDemo!_woutput+0x22
       44 00033484 00415eed StackOvfDemo!wprintf+0x85
       d8 0003355c 00415cc5 StackOvfDemo!ProcessStringW+0x2d
    fc878 0012fdd4 00415a44 StackOvfDemo!ProcessStrings+0xe5
      108 0012fedc 0041c043 StackOvfDemo!main+0x64
       e4 0012ffc0 7c4e87f5 StackOvfDemo!mainCRTStartup+0x183
       30 0012fff0 00000000 KERNEL32!BaseProcessStart+0x3d
注意第一列的內容??它報告棧上函數所占用的字節數。很顯然,ProcessStrings函數用了可用棧空間的最大份額,因此,它可能要為棧溢出負責。

如果你想知道ProcessStrings函數為什么需要如此多的??臻g,這里有一些解釋。這個函數使用ATL的A2W宏把字符串從ANSI格式轉換成Unicode格式,這個宏在內部用_alloca函數在棧上分配內存。用_alloca分配的內存只有當它的調用者(在這個例子里是ProcessStrings)返回后才被釋放。直到ProcessStrings返回控制之前,A2W(因此,也就是_alloca)在棧上為每個后續的調用分配另外的空間,這將迅速耗盡棧空間。
底線:不要在循環里使用_alloca。

posted on 2009-07-09 13:25 yanghaibao 閱讀(346) 評論(0)  編輯 收藏 引用

導航

<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

統計

常用鏈接

留言簿

隨筆分類

隨筆檔案

文章檔案

收藏夾

Good blogs

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美成人激情在线| 卡一卡二国产精品| 黄色成人精品网站| 国产亚洲成精品久久| 国产精品家庭影院| 国产亚洲午夜高清国产拍精品| 国产精品色在线| 国产亚洲欧美另类中文| 亚洲国内精品在线| 亚洲女同精品视频| 麻豆成人综合网| 亚洲免费观看在线观看| 亚洲尤物精选| 久久久综合精品| 欧美日韩视频专区在线播放 | 国产精品每日更新| 欧美色视频日本高清在线观看| 国产精品久久久久久久久久妞妞 | 国产欧美日本一区二区三区| 国一区二区在线观看| 亚洲精品中文字幕女同| 亚洲欧美日韩精品一区二区 | 亚洲专区在线视频| 久久综合99re88久久爱| 国产精品久久久久9999高清| 激情欧美国产欧美| 亚洲网站视频福利| 美女视频一区免费观看| 亚洲蜜桃精久久久久久久| 久久国产精彩视频| 国产精品高潮久久| 亚洲欧洲日本一区二区三区| 性欧美8khd高清极品| 亚洲级视频在线观看免费1级| 一个人看的www久久| 欧美aⅴ99久久黑人专区| 国产亚洲成年网址在线观看| 亚洲一区二区三区免费观看| 欧美激情精品久久久久久黑人| 午夜免费日韩视频| 国产精品久久久久9999| 99热精品在线| 亚洲国产mv| 免费永久网站黄欧美| 精品二区视频| 久久综合亚州| 欧美在线播放视频| 国产视频欧美视频| 欧美一区亚洲| 亚洲午夜精品久久久久久浪潮| 欧美激情一区二区| 亚洲精品在线视频观看| 亚洲国产精品电影在线观看| 久久激情五月婷婷| 国产综合色在线| 久久久噜噜噜| 久久精选视频| 亚洲国产精品久久精品怡红院 | 亚洲精品影视| 欧美黄污视频| 蜜桃久久av一区| 91久久精品一区二区别| 欧美成人一区二区三区在线观看| 久久精品视频播放| 伊人影院久久| 亚洲国产日韩欧美综合久久| 男人的天堂成人在线| 美女诱惑一区| 国产美女在线精品免费观看| 亚洲乱码久久| 日韩西西人体444www| 欧美性猛交一区二区三区精品| 日韩一级免费观看| 在线一区二区三区四区五区| 国产精品欧美经典| 久久亚洲国产精品一区二区| 久久九九国产精品| 99国产一区| 午夜精品一区二区三区在线播放| 国产亚洲精品成人av久久ww| 老巨人导航500精品| 欧美电影免费观看| 亚洲永久在线观看| 久久精品国产精品亚洲综合| 在线高清一区| 亚洲美女在线视频| 国内精品视频666| 亚洲精品免费在线| 国产欧美一区二区三区另类精品| 久久婷婷激情| 欧美日韩一卡| 免费成人在线观看视频| 欧美日韩一区二区在线观看| 久久精品一级爱片| 欧美另类极品videosbest最新版本 | 久久影院亚洲| 欧美激情一区二区三区全黄| 午夜久久久久| 欧美高清在线视频观看不卡| 亚洲欧美www| 免费在线播放第一区高清av| 亚洲欧美中文另类| 欧美精品性视频| 久久性色av| 国产欧美日本一区视频| 亚洲精品日本| 91久久精品一区二区三区| 亚洲一区二区三区在线观看视频| 亚洲国产精品视频一区| 亚洲欧美视频在线观看| 一区二区毛片| 欧美激情精品久久久久久变态| 久久久久久噜噜噜久久久精品| 欧美精品一区二区三区在线播放 | 欧美激情一区在线| 久久中文欧美| 国产精品中文字幕欧美| 亚洲美女免费精品视频在线观看| 狠狠色2019综合网| 亚洲女人小视频在线观看| 99亚洲一区二区| 嫩草影视亚洲| 欧美18av| 亚洲电影在线| 久久亚洲不卡| 亚洲国产女人aaa毛片在线| 国产一区视频观看| 久久在线视频在线| 欧美99在线视频观看| 亚洲欧美国产不卡| 99精品视频免费全部在线| 99热这里只有精品8| 久久久久久尹人网香蕉| 性久久久久久久久久久久| 亚洲精品日韩久久| 亚洲国产另类精品专区| 国产伦精品一区二区三区在线观看| 久久久www| 欧美护士18xxxxhd| 亚洲校园激情| 国产精品福利在线| 亚洲破处大片| 亚洲二区在线视频| 久久亚洲私人国产精品va媚药| 国产精品久久久久久久久搜平片| 亚洲人成网站999久久久综合| 亚洲日韩视频| 欧美刺激性大交免费视频| 欧美激情综合色| 亚洲三级电影在线观看| 欧美激情在线播放| 亚洲精品久久久蜜桃| 一区二区三区黄色| 国产精品sm| 欧美一区二视频| 免费观看亚洲视频大全| 亚洲激情视频在线| 欧美日韩视频| 亚洲天堂激情| 久久免费视频这里只有精品| 在线免费不卡视频| 欧美大色视频| 亚洲天堂久久| 欧美国产欧美亚洲国产日韩mv天天看完整 | 亚洲色图在线视频| 久久超碰97人人做人人爱| 韩国av一区二区三区在线观看 | 国产一区二区三区电影在线观看| 久久久噜噜噜久久中文字幕色伊伊| 欧美成人精品一区二区三区| 中文亚洲欧美| 国产主播一区| 欧美金8天国| 性做久久久久久久免费看| 亚洲高清激情| 欧美一区二区黄| 亚洲精品久久久久| 国产精品一区视频| 久久综合色婷婷| 亚洲欧美亚洲| 国产麻豆日韩| 亚洲人成在线播放| 国产一区二区三区四区五区美女 | 亚洲一区二区不卡免费| 女生裸体视频一区二区三区| 一区二区三区产品免费精品久久75 | 中文网丁香综合网| 悠悠资源网久久精品| 国产精品盗摄久久久| 免费看成人av| 欧美在线视频观看| 亚洲免费视频观看| 日韩亚洲综合在线| 亚洲第一在线综合网站| 欧美伊人久久久久久久久影院| 日韩视频在线观看| 亚洲高清一二三区| 韩国v欧美v日本v亚洲v| 国产精品乱码一区二区三区| 欧美精品aa|