from: http://rendao.org/blog/1999/
Debug系列:VC++程序Release版崩溃的解决办法
VC++程序发布后,如果在客户那运行崩溃,且研发环境下无法本地复现,工程师可能就要去现场,如果在现场也只是偶发的bug,去了现场也是抓狂。那,有什么办法能便于我们解决VC++程序生产环境下崩溃的问题呢?
常用方法,为你的程序加入Dump机制。
网上流传已久的miniDump方法是可行的,某国外程序员写的miniDump.h和miniDump.cpp,把这个模块加入你的VC++工程就可以了。miniDump模块添加办法如下:
Setp1:在需要生成dump文件的工程中引用包含MiniDump.h,并且在程序初始化时调用minidump_startup, 程序退出时调用minidump_cleanup
Step2: 在工程release设置中,VC6下务必保证勾选了“产生调试信息”和“产生MAP文件”,VC2012下进入“配置属性|链接器|全部选项”,“生成调试信息”选择“是”,“生成映射文件”选择“是”,“引用”选择“是(/OPT:REF) ”。
Step3: 编译后生成的pdb、源码文件都需要保存,以便以后可辅助分析dump文件。本文的崩溃分析方法中未用到map文件,据说pdb就够了,但最好还是保存下来备用。
miniDump.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#ifndef MINIDUMP_DEF
#define MINIDUMP_DEF
#include <windows.h>
#include <tlhelp32.h>
#include "StdAfx.h"
//#include "dbghelp.h"
//#define DEBUG_DPRINTF 1
#define CRASHREPORT_DIR "CrashReport"
#pragma optimize("y", off) //generate stack frame pointers for all functions - same as /Oy- in the project
#pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union
#pragma warning(disable: 4100) //unreferenced formal parameter
/*BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr);
int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str);
int WINAPI Get_Version_Str(PCHAR Str);
PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException);
void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);*/
// In case you don't have dbghelp.h.
#ifndef _DBGHELP_
typedef
struct
_MINIDUMP_EXCEPTION_INFORMATION
{
DWORD
ThreadId
;
PEXCEPTION_POINTERS
ExceptionPointers
;
BOOL
ClientPointers
;
}
MINIDUMP_EXCEPTION_INFORMATION
,
*
PMINIDUMP_EXCEPTION_INFORMATION
;
typedef
enum
_MINIDUMP_TYPE
{
MiniDumpNormal
=
0x00000000
,
MiniDumpWithDataSegs
=
0x00000001
,
}
MINIDUMP_TYPE
;
typedef
BOOL
(
WINAPI
*
MINIDUMP_WRITE_DUMP
)
(
IN
HANDLE
hProcess
,
IN
DWORD
ProcessId
,
IN
HANDLE
hFile
,
IN
MINIDUMP_TYPE
DumpType
,
IN
CONST
PMINIDUMP_EXCEPTION_INFORMATION
ExceptionParam
,
OPTIONAL
IN
PVOID
UserStreamParam
,
OPTIONAL
IN
PVOID
CallbackParam
OPTIONAL
)
;
#else
typedef
BOOL
(
WINAPI
*
MINIDUMP_WRITE_DUMP
)
(
IN
HANDLE
hProcess
,
IN
DWORD
ProcessId
,
IN
HANDLE
hFile
,
IN
MINIDUMP_TYPE
DumpType
,
IN
CONST
PMINIDUMP_EXCEPTION_INFORMATION
ExceptionParam
,
OPTIONAL
IN
PMINIDUMP_USER_STREAM_INFORMATION
UserStreamParam
,
OPTIONAL
IN
PMINIDUMP_CALLBACK_INFORMATION
CallbackParam
OPTIONAL
)
;
#endif //#ifndef _DBGHELP_
// Tool Help functions.
typedef
HANDLE
(
WINAPI
*
CREATE_TOOL_HELP32_SNAPSHOT
)
(
DWORD
dwFlags
,
DWORD
th32ProcessID
)
;
typedef
BOOL
(
WINAPI
*
MODULE32_FIRST
)
(
HANDLE
hSnapshot
,
LPMODULEENTRY32
lpme
)
;
typedef
BOOL
(
WINAPI
*
MODULE32_NEST
)
(
HANDLE
hSnapshot
,
LPMODULEENTRY32
lpme
)
;
extern
void
WINAPI
Create_Dump
(
PEXCEPTION_POINTERS
pException
,
BOOL
File_Flag
,
BOOL
Show_Flag
)
;
extern
HMODULE
hDbgHelp
;
extern
MINIDUMP_WRITE_DUMP
MiniDumpWriteDump_
;
extern
CREATE_TOOL_HELP32_SNAPSHOT
CreateToolhelp32Snapshot_
;
extern
MODULE32_FIRST
Module32First_
;
extern
MODULE32_NEST
Module32Next_
;
//崩溃后的回调函数,在这里创建dump文件
inline
LONG
WINAPI
CrashReportEx
(
LPEXCEPTION_POINTERS
ExceptionInfo
)
{
char
szFileName
[
MAX_PATH
]
=
{
0x00
}
;
UINT
nRet
=
0
;
// 重启程序,也可以不重启,因为如果是启动时程序就崩溃的话,将产生多个dump文件
//::GetModuleFileName(NULL, szFileName, MAX_PATH);
//nRet = WinExec(szFileName, SW_SHOW);
// 创建DUMP文件
Create_Dump
(
ExceptionInfo
,
1
,
1
)
;
return
EXCEPTION_EXECUTE_HANDLER
;
}
//对外接口,一般在程序初始化时调用此函数,然后此程序即拥有了崩溃后生成dump文件的功能
inline
void
*
minidump_startup
(
)
{
SetUnhandledExceptionFilter
(
CrashReportEx
)
;
//CrashReportEx是回调函数
HMODULE
hKernel32
;
// Try to get MiniDumpWriteDump() address.
hDbgHelp
=
LoadLibrary
(
"DBGHELP.DLL"
)
;
MiniDumpWriteDump_
=
(
MINIDUMP_WRITE_DUMP
)
GetProcAddress
(
hDbgHelp
,
"MiniDumpWriteDump"
)
;
// d("hDbgHelp=%X, MiniDumpWriteDump_=%X", hDbgHelp, MiniDumpWriteDump_);
// Try to get Tool Help library functions.
hKernel32
=
GetModuleHandle
(
"KERNEL32"
)
;
CreateToolhelp32Snapshot_
=
(
CREATE_TOOL_HELP32_SNAPSHOT
)
GetProcAddress
(
hKernel32
,
"CreateToolhelp32Snapshot"
)
;
Module32First_
=
(
MODULE32_FIRST
)
GetProcAddress
(
hKernel32
,
"Module32First"
)
;
Module32Next_
=
(
MODULE32_NEST
)
GetProcAddress
(
hKernel32
,
"Module32Next"
)
;
return
hDbgHelp
;
}
inline
void
minidump_cleanup
(
void
*
handle
)
{
if
(
handle
)
{
FreeLibrary
(
(
HMODULE
)
handle
)
;
}
}
#endif
|
miniDump.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
/*
Author: Vladimir Sedach.
Purpose: demo of Call Stack creation by our own means,
and with MiniDumpWriteDump() function of DbgHelp.dll.
*/
#include "StdAfx.h"
#include <afx.h> //CString
#include <AfxWin.h> //AfxGetInstanceHandle
#include "MiniDump.h"
#include <Shlwapi.h>
#pragma comment(lib,"shlwapi.lib")
HMODULE
hDbgHelp
;
MINIDUMP_WRITE_DUMP
MiniDumpWriteDump_
;
CREATE_TOOL_HELP32_SNAPSHOT
CreateToolhelp32Snapshot_
;
MODULE32_FIRST
Module32First_
;
MODULE32_NEST
Module32Next_
;
#define DUMP_SIZE_MAX 8000 //max size of our dump
#define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls
#define NL "\r\n" //new line
CString
GetExePath
(
)
{
char
sFileName
[
256
]
=
{
0
}
;
CString
sPath
=
_T
(
""
)
;
GetModuleFileName
(
AfxGetInstanceHandle
(
)
,
sFileName
,
255
)
;
sPath
.
Format
(
"%s"
,
sFileName
)
;
int
pos
=
sPath
.
ReverseFind
(
'\\'
)
;
if
(
pos
!=
-
1
)
sPath
=
sPath
.
Left
(
pos
)
;
else
sPath
=
_T
(
""
)
;
return
sPath
;
}
BOOL
WINAPI
Get_Module_By_Ret_Addr
(
PBYTE
Ret_Addr
,
PCHAR
Module_Name
,
PBYTE
&
Module_Addr
)
// Find module by Ret_Addr (address in the module).
// Return Module_Name (full path) and Module_Addr (start address).
// Return TRUE if found.
{
MODULEENTRY32
M
=
{
sizeof
(
M
)
}
;
HANDLE
hSnapshot
;
Module_Name
[
0
]
=
0
;
if
(
CreateToolhelp32Snapshot_
)
{
hSnapshot
=
CreateToolhelp32Snapshot_
(
TH32CS_SNAPMODULE
,
0
)
;
if
(
(
hSnapshot
!=
INVALID_HANDLE_VALUE
)
&&
Module32First_
(
hSnapshot
,
&M
)
)
{
do
{
if
(
DWORD
(
Ret_Addr
-
M
.
modBaseAddr
)
<
M
.
modBaseSize
)
{
lstrcpyn
(
Module_Name
,
M
.
szExePath
,
MAX_PATH
)
;
Module_Addr
=
M
.
modBaseAddr
;
break
;
}
}
while
(
Module32Next_
(
hSnapshot
,
&M
)
)
;
}
CloseHandle
(
hSnapshot
)
;
}
return
!
!
Module_Name
[
0
]
;
}
//Get_Module_By_Ret_Addr
int
WINAPI
Get_Call_Stack
(
PEXCEPTION_POINTERS
pException
,
PCHAR
Str
)
// Fill Str with call stanbsp;ck info.
// pException can be either GetExceptionInformation() or NULL.
// If pException = NULL - get current call stack.
{
CHAR
Module_Name
[
MAX_PATH
]
;
PBYTE
Module_Addr
=
0
;
PBYTE
Module_Addr_1
;
int
Str_Len
;
typedef
struct
STACK
{
STACK
*
Ebp
;
PBYTE
Ret_Addr
;
DWORD
Param
[
0
]
;
}
STACK
,
*
PSTACK
;
STACK
Stack
=
{
0
,
0
}
;
PSTACK
Ebp
;
if
(
pException
)
//fake frame for exception address
{
Stack
.
Ebp
=
(
PSTACK
)
pException
->
ContextRecord
->
Ebp
;
Stack
.
Ret_Addr
=
(
PBYTE
)
pException
->
ExceptionRecord
->
ExceptionAddress
;
Ebp
=
&Stack
;
}
else
{
Ebp
=
(
PSTACK
)
&pException
-
1
;
//frame addr of Get_Call_Stack()
// Skip frame of Get_Call_Stack().
if
(
!
IsBadReadPtr
(
Ebp
,
sizeof
(
PSTACK
)
)
)
Ebp
=
Ebp
->
Ebp
;
//caller ebp
}
Str
[
0
]
=
0
;
Str_Len
=
0
;
// Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
// Break trace on wrong stack frame.
for
(
int
Ret_Addr_I
=
0
;
(
Ret_Addr_I
<
CALL_TRACE_MAX
)
&&
!
IsBadReadPtr
(
Ebp
,
sizeof
(
PSTACK
)
)
&&
!
IsBadCodePtr
(
FARPROC
(
Ebp
->
Ret_Addr
)
)
;
Ret_Addr_I
++
,
Ebp
=
Ebp
->
Ebp
)
{
// If module with Ebp->Ret_Addr found.
if
(
Get_Module_By_Ret_Addr
(
Ebp
->
Ret_Addr
,
Module_Name
,
Module_Addr_1
)
)
{
if
(
Module_Addr_1
!=
Module_Addr
)
//new module
{
// Save module's address and full path.
Module_Addr
=
Module_Addr_1
;
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"%08X %s"
,
Module_Addr
,
Module_Name
)
;
}
// Save call offset.
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
" +%08X"
,
Ebp
->
Ret_Addr
-
Module_Addr
)
;
// Save 5 params of the call. We don't know the real number of params.
if
(
pException
&&
!
Ret_Addr_I
)
//fake frame for exception address
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
" Exception Offset"
)
;
else
if
(
!
IsBadReadPtr
(
Ebp
,
sizeof
(
PSTACK
)
+
5
*
sizeof
(
DWORD
)
)
)
{
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
" (%X, %X, %X, %X, %X)"
,
Ebp
->
Param
[
0
]
,
Ebp
->
Param
[
1
]
,
Ebp
->
Param
[
2
]
,
Ebp
->
Param
[
3
]
,
Ebp
->
Param
[
4
]
)
;
}
}
else
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"%08X"
,
Ebp
->
Ret_Addr
)
;
}
return
Str_Len
;
}
//Get_Call_Stack
int
WINAPI
Get_Version_Str
(
PCHAR
Str
)
// Fill Str with Windows version.
{
OSVERSIONINFOEX
V
=
{
sizeof
(
OSVERSIONINFOEX
)
}
;
//EX for NT 5.0 and later
if
(
!
GetVersionEx
(
(
POSVERSIONINFO
)
&V
)
)
{
ZeroMemory
(
&V
,
sizeof
(
V
)
)
;
V
.
dwOSVersionInfoSize
=
sizeof
(
OSVERSIONINFO
)
;
GetVersionEx
(
(
POSVERSIONINFO
)
&V
)
;
}
if
(
V
.
dwPlatformId
!=
VER_PLATFORM_WIN32_NT
)
V
.
dwBuildNumber
=
LOWORD
(
V
.
dwBuildNumber
)
;
//for 9x HIWORD(dwBuildNumber) = 0x04xx
return
wsprintf
(
Str
,
NL
"Windows: %d.%d.%d, SP %d.%d, Product Type %d"
,
//SP - service pack, Product Type - VER_NT_WORKSTATION,...
V
.
dwMajorVersion
,
V
.
dwMinorVersion
,
V
.
dwBuildNumber
,
V
.
wServicePackMajor
,
V
.
wServicePackMinor
/*, V.wProductType*/
)
;
}
//Get_Version_Str
PCHAR
WINAPI
Get_Exception_Info
(
PEXCEPTION_POINTERS
pException
)
// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.
{
PCHAR
Str
;
int
Str_Len
;
int
i
;
CHAR
Module_Name
[
MAX_PATH
]
;
PBYTE
Module_Addr
;
HANDLE
hFile
;
FILETIME
Last_Write_Time
;
FILETIME
Local_File_Time
;
SYSTEMTIME
T
;
Str
=
new
CHAR
[
DUMP_SIZE_MAX
]
;
if
(
!
Str
)
return
NULL
;
Str_Len
=
0
;
Str_Len
+=
Get_Version_Str
(
Str
+
Str_Len
)
;
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Process: "
)
;
GetModuleFileName
(
NULL
,
Str
+
Str_Len
,
MAX_PATH
)
;
Str_Len
=
lstrlen
(
Str
)
;
// If exception occurred.
if
(
pException
)
{
EXCEPTION_RECORD
&
E
=
*
pException
->
ExceptionRecord
;
CONTEXT
&
C
=
*
pException
->
ContextRecord
;
// If module with E.ExceptionAddress found - save its path and date.
if
(
Get_Module_By_Ret_Addr
(
(
PBYTE
)
E
.
ExceptionAddress
,
Module_Name
,
Module_Addr
)
)
{
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Module: %s"
,
Module_Name
)
;
if
(
(
hFile
=
CreateFile
(
Module_Name
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
OPEN_EXISTING
,
FILE_ATTRIBUTE_NORMAL
,
NULL
)
)
!=
INVALID_HANDLE_VALUE
)
{
if
(
GetFileTime
(
hFile
,
NULL
,
NULL
,
&Last_Write_Time
)
)
{
FileTimeToLocalFileTime
(
&Last_Write_Time
,
&Local_File_Time
)
;
FileTimeToSystemTime
(
&Local_File_Time
,
&T
)
;
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Date Modified: %02d/%02d/%d"
,
T
.
wMonth
,
T
.
wDay
,
T
.
wYear
)
;
}
CloseHandle
(
hFile
)
;
}
}
else
{
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Exception Addr: %08X"
,
E
.
ExceptionAddress
)
;
}
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Exception Code: %08X"
,
E
.
ExceptionCode
)
;
if
(
E
.
ExceptionCode
==
EXCEPTION_ACCESS_VIOLATION
)
{
// Access violation type - Write/Read.
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"%s Address: %08X"
,
(
E
.
ExceptionInformation
[
0
]
)
?
"Write"
:
"Read"
,
E
.
ExceptionInformation
[
1
]
)
;
}
// Save instruction that caused exception.
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Instruction: "
)
;
for
(
i
=
0
;
i
<
16
;
i
++
)
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
" %02X"
,
PBYTE
(
E
.
ExceptionAddress
)
[
i
]
)
;
// Save registers at exception.
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Registers:"
)
;
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"EAX: %08X EBX: %08X ECX: %08X EDX: %08X"
,
C
.
Eax
,
C
.
Ebx
,
C
.
Ecx
,
C
.
Edx
)
;
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"ESI: %08X EDI: %08X ESP: %08X EBP: %08X"
,
C
.
Esi
,
C
.
Edi
,
C
.
Esp
,
C
.
Ebp
)
;
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"EIP: %08X EFlags: %08X"
,
C
.
Eip
,
C
.
EFlags
)
;
}
//if (pException)
// Save call stack info.
Str_Len
+=
wsprintf
(
Str
+
Str_Len
,
NL
"Call Stack:"
)
;
Get_Call_Stack
(
pException
,
Str
+
Str_Len
)
;
if
(
Str
[
0
]
==
NL
[
0
]
)
lstrcpy
(
Str
,
Str
+
sizeof
(
NL
)
-
1
)
;
return
Str
;
}
//Get_Exception_Info
void
WINAPI
Create_Dump
(
PEXCEPTION_POINTERS
pException
,
BOOL
File_Flag
,
BOOL
Show_Flag
)
// Create dump.
// pException can be either GetExceptionInformation() or NULL.
// If File_Flag = TRUE - write dump files (.dmz and .dmp) with the name of the current process.
// If Show_Flag = TRUE - show message with Get_Exception_Info() dump.
{
HANDLE
hDump_File
;
PCHAR
Str
;
DWORD
Bytes
;
DWORD
nLen
=
0
;
CString
strDir
,
strTXTFile
,
strDMPFile
;
CString
strDate
,
strTotal
;
CTime
tm
=
CTime
::
GetCurrentTime
(
)
;
strDir
.
Format
(
_T
(
"%s\\%s"
)
,
GetExePath
(
)
,
CRASHREPORT_DIR
)
;
strTXTFile
.
Format
(
_T
(
"%s\\%s\\%04d-%02d-%02d %02d-%02d-%02d.txt"
)
,
GetExePath
(
)
,
CRASHREPORT_DIR
,
tm
.
GetYear
(
)
,
tm
.
GetMonth
(
)
,
tm
.
GetDay
(
)
,
tm
.
GetHour
(
)
,
tm
.
GetMinute
(
)
,
tm
.
GetSecond
(
)
)
;
strDMPFile
.
Format
(
_T
(
"%s\\%s\\%04d-%02d-%02d %02d-%02d-%02d.dmp"
)
,
GetExePath
(
)
,
CRASHREPORT_DIR
,
tm
.
GetYear
(
)
,
tm
.
GetMonth
(
)
,
tm
.
GetDay
(
)
,
tm
.
GetHour
(
)
,
tm
.
GetMinute
(
)
,
tm
.
GetSecond
(
)
)
;
if
(
!
PathFileExists
(
strDir
)
)
CreateDirectory
(
strDir
,
NULL
)
;
Str
=
Get_Exception_Info
(
pException
)
;
//if (Show_Flag && Str)
// MessageBox(NULL, Str, "MiniDump", MB_ICONHAND | MB_OK);
if
(
File_Flag
)
{
if
(
Str
)
{
hDump_File
=
CreateFile
(
strTXTFile
,
GENERIC_WRITE
,
0
,
NULL
,
CREATE_ALWAYS
,
FILE_ATTRIBUTE_NORMAL
,
NULL
)
;
nLen
=
lstrlen
(
Str
)
;
Str
[
nLen
]
=
'\0'
;
WriteFile
(
hDump_File
,
Str
,
lstrlen
(
Str
)
+
1
,
&Bytes
,
NULL
)
;
CloseHandle
(
hDump_File
)
;
}
// If MiniDumpWriteDump() of DbgHelp.dll available.
if
(
MiniDumpWriteDump_
)
{
MINIDUMP_EXCEPTION
_INFORMATION
M
;
M
.
ThreadId
=
GetCurrentThreadId
(
)
;
M
.
ExceptionPointers
=
pException
;
M
.
ClientPointers
=
0
;
hDump_File
=
CreateFile
(
strDMPFile
,
GENERIC_WRITE
,
0
,
NULL
,
CREATE_ALWAYS
,
FILE_ATTRIBUTE_NORMAL
,
NULL
)
;
MiniDumpWriteDump_
(
GetCurrentProcess
(
)
,
GetCurrentProcessId
(
)
,
hDump_File
,
MiniDumpNormal
,
(
pException
)
?
&M
:
NULL
,
NULL
,
NULL
)
;
CloseHandle
(
hDump_File
)
;
}
}
//if (File_Flag)
delete
Str
;
}
//Create_Dump
|
补充说明
据说此法无法检测内存溢出、内存覆盖的错误,我简单验证过,基本是这样,比如:
遇到这样的错误崩溃,会生成dump文件
char* s=NULL;
s[1] = ‘a’;
遇到这样的错误崩溃,可能不会生成dump文件,
char s[10];
sprintf_s(s,10,”hello%d”,”abcdefghijklmnopqrstuvwxyz”);
遇到这样的错误崩溃,可能不会生成dump文件
char s[10];
sprintf_s(s,10,”hello%s”,”abcdefghijklmnopqrstuvwxyz”);
Dump文件有了,那如何使用Dump文件来排错呢?
Step1:四个准备文件
打开WinDbg -> 设置pdb路径(File|Symbol File Path) -> 设置源代码路径(File|Source File Path) -> 设置Exe路径(File|Image File Path) -> 打开dump文件(File|Open Crash Dump)。
如果只设置pdb文件路径,也是可以显示出错信息的,只是不够详细。
Step2: 分析定位
7、输入命令!analyze -v,等待几秒后会打印出错误信息,函数调用栈,并定位到出错代码
OK ,这样我们就能在发布版本的程序中,准确的定位到哪个函数出了问题