編程序最怕的就是報內存錯誤,而這種錯誤又是經(jīng)常出現的,當錯誤發(fā)生在debug下時(shí)可以通過(guò)調試找到錯誤所在,而在release下則不可以,這時(shí)可以利用map文件定位到發(fā)生錯誤的語(yǔ)句。注意不要相信在release下報錯后進(jìn)行調試所指向的錯誤所在。
首先設定能生成map文件
項目---屬性---配置屬性---連接器---調試下,生成映射文件:是(/MAP) 映射文件名:$(IntDir)/XXX.map ,一個(gè)工程生成一個(gè)map文件
設置生成cod文件
項目--屬性----配置屬性---C/C++---輸出文件下,匯編輸出:程序集、機器碼和源代碼(/FAcs)。一個(gè)cpp文件生成一個(gè)cod文件。
重新生成解決方案后可在release文件夾下看到生成的map文件和cod文件。
下面說(shuō)名如何通過(guò)這兩種文件找到錯誤所在。
簡(jiǎn)單例子:
(1) #include "stdafx.h"
void errorFun(int * p)
{
*p=1;
}
int _tmain(int argc, _TCHAR* argv[])
{
int * p=NULL;
errorFun(p);
return 0;
}
在errorFun中函數中,*p=1這一行出錯,由于p沒(méi)有申請空間,運行時(shí)出錯,彈出Unhandled exception at 0x004113b1 in testError.exe: 0xC0000005: Access violation writing location 0x00000000.在0x004113b1程序發(fā)生崩潰。
打開(kāi)map文件,定位崩潰函數.
map文件開(kāi)頭是一些鏈接信息,然后我們要找函數和實(shí)始地址信息。地址是函始的開(kāi)始地址
Address Publics by Value Rva+Base Lib:Object
0000:00000000 ___safe_se_handler_count 00000000 <absolute>
0000:00000000 ___safe_se_handler_table 00000000 <absolute>
0000:00000000 ___ImageBase 00400000 <linker-defined>
0001:00000000 __enc$textbss$begin 00401000 <linker-defined>
0001:00010000 __enc$textbss$end 00411000 <linker-defined>
0002:00000390 errorFun@@YAXPAH@Z 00411390 f testError.obj
0002:000003d0 _wmain 004113d0 f testError.obj
0002:00000430 __RTC_InitBase 00411430 f MSVCRTD:init.obj
0002:00000470 __RTC_Shutdown 00411470 f MSVCRTD:init.obj
0002:00000490 __RTC_CheckEsp 00411490 f MSVCRTD:stack.obj
0002:000004c0 @_RTC_CheckStackVars@8 004114c0 f MSVCRTD:stack.obj
0002:00000540 @_RTC_AllocaHelper@12 00411540 f MSVCRTD:stack.obj
....
程序崩潰地址0x004113b1,我們找到第一個(gè)比這個(gè)地址大的004113d0,前一個(gè)是00411390,地址是函數的開(kāi)始地址,所以發(fā)生的崩潰的的函數是errorFun,這個(gè)函數的初始地址00411390.
通過(guò)cod文件找出具體崩潰行號.
由(2)可知,發(fā)生錯誤函數是errorFun,在testError.obj,打開(kāi)testError.cod文件,找到errorFun函數生成的機器碼.
errorFun@@YAXPAH@Z PROC ; errorFun, COMDAT
; 7 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 81 ec c0 00 00
00 sub esp, 192 ; 000000c0H
00009 53 push ebx
0000a 56 push esi
0000b 57 push edi
0000c 8d bd 40 ff ff
ff lea edi, DWORD PTR [ebp-192]
00012 b9 30 00 00 00 mov ecx, 48 ; 00000030H
00017 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
0001c f3 ab rep stosd
; 8 : *p=1;
0001e 8b 45 08 mov eax, DWORD PTR _p$[ebp]
00021 c7 00 01 00 00
00 mov DWORD PTR [eax], 1
; 9 : }
00027 5f pop edi
00028 5e pop esi
00029 5b pop ebx
0002a 8b e5 mov esp, ebp
0002c 5d pop ebp
0002d c3 ret 0
(說(shuō)明: 7,8,9是表示在源代碼的行號。00000 55 push ebp,000000是相對偏移地地,55是機器碼號,push ebp,000000是匯編碼。)
我們計算相對偏移地址,即崩潰地址-函數起始地址,0x004113b1-0x00411390=0x21(16進(jìn)制的計數)找到0x21這一行對應的機器碼是 00021 c7 00 01 00 00,向上看它是由第8行*p=1;生成的匯編碼,由此可見(jiàn)是這一行程序發(fā)生崩潰。
這樣就找到了報內存錯誤的罪魁禍首了。
聯(lián)系客服