對 User breakpoint called from code at XXX 問題分析彙總

分析一,轉自獨奏的同名Bloghtml

      今天調試程序時在Debug版跳出這個錯誤,我程序根本沒設置斷點,而其好像說是個人堆有問題,而編譯了個Release版本運行正常,後來google下,查到以下解釋:編程

      說是調試狀態下,操做系統用DebugWin32Heap來替代正常的heap分配內存空間。在這個堆上的任何操做debug的堆管理器會檢查堆的數據完整性,若是它發現了一個錯誤,就會報告一個消息上來。當一個應用程序PageHeap機制被激活時,該應用程序的全部的堆分配被放到內存中,這樣堆的邊界就與虛擬內存的邊界排在一塊兒了。與堆相鄰的虛擬內存頁面被設置爲NO_ACCESS。在該應用程序中對堆後面的空間的訪問就會馬上引發錯誤,這就能夠在一個調試工具中被捕獲。在釋放堆時,過程與之相似。PageHeap修改釋放的應用程序虛擬頁面爲NO_ACCESS,這樣,若是應用程序試圖讀寫該內存時就會發生訪問錯誤。windows

      既然是Heap的問題我就查遍了全部源代碼的new和delete操做的代碼,感受沒有任何問題,該分配的都分配了該釋放的也都釋放了,並且沒有錯誤狀況。後來沒辦法弄個極端的,我把程序的中全部delete 的語句所有註釋,再運行程序果真沒問題了- - 。我又繼續查了下程序,感受仍是沒問題。後來定位到一條delete, 只要有它程序就報錯,沒有就正常。這個delete位於一個移除服務的函數中,這裏有必要說下個人程序結構app

      我將服務所有存入dll中,主要函數一個四個(其餘的就不說了)
      createSrv 創建服務 removeSrv 移除服務 runSrv 運行服務 stopSrv 中止服務函數

      而這個delete正好位於removeSrv中,可是個人delete沒有任何問題。後來沒辦法又google下,找到了一個和我遇到一樣問題的人,引用原文以下:工具

      "重複釋放致使的問題,User breakpoint called from code at 0x77f9193c ,以上緣由是因爲釋放了一個類的員,最後在做該類的析構時因爲它的成員已經被釋放致使出錯(該成員被釋放可是沒有設 NULL)"this

      看完這句話後我馬上去看個人類的析構函數(因爲個人dll爲了通用並非導出類而是導出函數,而我調用方編寫了調用類來調用dll導出函數,到統一管理和封裝的目的)。果真 - -|| :我怕萬一個人調用沒有" stopSrv 中止服務"和"removeSrv 移除服務" ,我在析構函數中又調用了這個兩個函數,鬱悶我從9點陸陸續續調試到如今 - - ......寫此文章警示後人......
google

分析二轉自除蟲記之十二:費解的NTDLL斷點編碼

好久沒有寫東西了,此次是爲了完善好久好久之前寫的一個培訓ppt(VC的使用與調試技巧),纔想起來寫點東西的。下面的文章參考了http://www.debuginfo.com/tips/userbpntdll.html,但不是翻譯,偶英語太爛了。

咱們在調試程序的過程當中,有時會忽然的顯示一個對話框,上面顯示這樣一條信息:
User breakpoint called from code at 0x77fa018c
或者是
Unhandled exception at 0x77f767cd (ntdll.dll) in myapp.exe: User breakpoint.
不過我遇到過的都是第一條信息,沒有遇到過第二條信息。spa

怎麼回事?咱們沒有設置斷點呀!爲何會有一個用戶斷點?而且這個問題看起來並無那麼嚴重,不在調試狀態下,程序正常運行,即便在調試狀態下咱們把這個對話框按了肯定後,再繼續F5,好像什麼事情也沒有發生,程序仍然在正常運行!

隱患!千萬不要忽視她!這個信息告訴咱們,程序中某個地方已經開始潰爛,若是你頻繁的碰到這個對話框,就說明潰爛已經擴大了。

若是你夠仔細,你會發如今你點了這個對話框的肯定按鈕以後,會在Output窗口中發現多了一行信息:
HEAP[DebugInfo2.exe]: Heap block at 00030FD8 modified at 00031010 past requested size of 30

查看堆棧窗口,裏面顯示這樣的信息:
NTDLL! 7c921230()
NTDLL! 7c97db9c()
NTDLL! 7c98cd11()
NTDLL! 7c980af8()
KERNEL32! 7c85e7af()
_CrtIsValidHeapPointer(const void * 0x00031000) line 1697
_free_dbg(void * 0x00031000, int 0x00000001) line 1044 + 9 bytes
operator delete(void * 0x00031000) line 49 + 16 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f15, int 0x00000001) line 13 + 15 bytes
WinMainCRTStartup() line 198 + 54 bytes
KERNEL32! 7c816d4f()

重現這樣的現場很容易的,只需幾行代碼就能夠了
char *p = new char[4];
lstrcpy(p, "this is a test");
delete p;

爲何會有這樣的信息消息框出現呢?這是由於若是咱們在調試狀態下,操做系統用DebugWin32Heap來替代正常的heap分配內存空間。在這個堆上的任何操做,debug的堆管理器會檢查堆的數據完整性,若是它發現了一個錯誤,就會報告一個消息上來。

那麼,咱們怎麼樣才能知道形成錯誤的緣由呢?若是隻是相似上面的演示代碼,不用任何技巧都能發現而且定位的。可是,絕大多數狀況下,Output窗口和CallStack窗口告訴咱們的信息都不能讓咱們精肯定位。

用BoundsChecker作運行期的檢查能夠查到這個錯誤的緣由,而且我我的認爲在程序發佈以前,在BoundsChecker下完整的跑一遍,檢查內存和資源是很是有必要的。可是每次都用BoundsChecker是比較麻煩的。

還有一個辦法,可讓這種定位更準確一點。那就是windows 2000 SP2以後提供的PageHeap機制。

下面的這段文字是別人寫的,我抄的,:)
當一個應用程序的PageHeap機制被激活時,該應用程序的全部的堆分配被放到內存中,這樣堆的 邊界就與虛擬內存的邊界排在一塊兒了。與堆相鄰的虛擬內存頁面被設置爲NO_ACCESS。在該應用程序中對堆後面的空間的訪問就會馬上引發錯誤,這就能夠 在一個調試工具中被捕獲。在釋放堆時,過程與之相似。PageHeap修改釋放的應用程序虛擬頁面爲NO_ACCESS,這樣,若是應用程序試圖讀寫該內 存時就會發生訪問錯誤。若是爲一個應用程序運行PageHeap特性,應用程序要比正常時運行得慢,而且須要更多的虛擬內存,由於每個堆的分配都須要兩 個完整的虛擬內存頁面。隨着應用程序對堆的使用的增長,可能須要增長系統的虛擬內存的大小,不然會出現虛擬內存不夠的錯誤信息。除非系統有至關大的虛擬內 存,不然建議不要同時運行兩個以上的激活了PageHeap特性的應用程序。

讓咱們的程序啓用Full Page Heap機制,只需在註冊表中
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\YourAppName.exe下增長以下設置:
GlobalFlag,字符串類型,值是x02200000
PageHeapFlags,字符串類型,值是0x3
VerifierFlags,DWORD類型,值是00000001
其中YourAppName.exe換成你的程序的名字,不要帶路徑。

若是嫌麻煩,你能夠到http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx下載Debugging Tools for Windows,安裝後,有一個gflags工具,使用下面的命令:
gflags –p /enable YourAppName.exe /full

這個工具幫你寫好了上面的註冊表項目。這個工具是一個GUI的程序,你能夠雙擊而且設置相關調試入口。

若是設置了Full PageHeap模式,咱們在調試運行的時候,那麼就會在彈出那個使人費解的斷點對話框以前出現一個斷言對話框,哈哈,這個對話框但是有一個Retry按鈕的,點擊以後進入CallStack,你能夠看到此時發生了什麼了。

若是你編寫的是一個dll,也可使用這個機制的,不過註冊表項下的值就要設置成以下:
GlobalFlag,字符串類型,值是0x02000000"
PageHeapTargetDlls,字符串類型,值是調試的dll名稱,不帶路徑
VerifierFlags,DWORD類型,值是00000001
PageHeapFlags,字符串類型,0x403

或者使用命令行
gflags –p /enable YourAppName.exe /full /dlls YourDll.dll

分析三,轉自jiahehao的同名Blog

在調試程序中遇到提示「user  breakpoint  called  from  code  at  0x......(地址)」時,這並不必定是因沒用戶設置了斷點的關係,而是由於系統執行了一個硬編碼斷點操做(hard  coded  breakpoint  instruction)。    

例如在Windows  NT下當正被調試的應用程序得到焦點時,若是F12鍵按下,則Windows  NT調用一個相似於DebugBreak()函數的函數,這個被調用的函數執行一個hard  coded  breakpoint  instruction,因而調試器捕捉到這個操做產生的例外,因此中斷並給出上述的提示(User  breakpoint  called  from  code  at  <address>)或者是給出Break  caused  by  hard  coded  breakpoint  instruction.,在這樣的狀況下,只要讓調試繼續進行便可(按下F5鍵)。     值得注意的是當程序涉及到全局性的共享內存(對象)時,如CShareFile,這些對象維護着一個全局性的內存塊,若是由於程序的疏忽對仍然鎖定的對象 (locked  object)進行釋放內存的話,則在NT下也會出現User  breakpoint  called  from  code  at  <address>這樣的提示。     此外,在低版本的Visual  C++調試器中,在很多地方(例如一些有關打印設備的操做)都用到GlobalLock,編程不當也會致使上述的提示出現,不過在win32中,不少這樣的調用已經再也不必要了。     但願這些信息能對您有所幫助,建議您檢查一些是否是程序當中有一些涉及到釋放全局性內存的操做。

相關文章
相關標籤/搜索