forked from Outerra/crashrpt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExceptionHandlerTests.cpp
341 lines (283 loc) · 13 KB
/
ExceptionHandlerTests.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
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/*************************************************************************************
This file is a part of CrashRpt library.
Copyright (c) 2003-2013 The CrashRpt project authors. All Rights Reserved.
Use of this source code is governed by a BSD-style license
that can be found in the License.txt file in the root of the source
tree. All contributing project authors may
be found in the Authors.txt file in the root of the source tree.
***************************************************************************************/
#include "stdafx.h"
#include "Tests.h"
#include "CrashRpt.h"
#include "Utility.h"
#include "strconv.h"
#include "TestUtils.h"
#include "strconv.h"
#include "CrashRptProbe.h"
#ifndef _DEBUG
class ExceptionHandlerTests : public CTestSuite
{
BEGIN_TEST_MAP(ExceptionHandlerTests, "Exception handler tests")
REGISTER_TEST(Test_CatchException)
END_TEST_MAP()
void SetUp();
void TearDown();
void Test_CatchException();
};
REGISTER_TEST_SUITE( ExceptionHandlerTests );
void ExceptionHandlerTests::SetUp()
{
}
void ExceptionHandlerTests::TearDown()
{
}
void ExceptionHandlerTests::Test_CatchException()
{
// This test is aimed to check if a CrashRpt-enabled client application catches
// the exceptions in its main and worker threads. This test runs the test app
// with special command line args to cause different types of exceptions in
// test app's main and worker thread and checks if crash report is generated
// and if exception type is correct.
CString sExePath = Utility::GetModuleName(NULL);
CString sTmpFolder;
struct _exception_param
{
LPCTSTR szCmdLine; // Command line arguments
LPCTSTR szExceptionType; // Expected exception type read from crash report (for main thread)
LPCTSTR szExceptionTypeInWorkerThread; // Expected exception type read from crash report (for worker thread)
};
const int PARAM_COUNT = 13;
_exception_param aParams[PARAM_COUNT] =
{
{_T("/exception /seh"), _T("11 SIGSEGV signal"), _T("0 SEH exception")},
{_T("/exception /terminate"), _T("1 terminate call"), _T("1 terminate call")},
{_T("/exception /unexpected"), _T("2 unexpected call"), _T("2 unexpected call")},
{_T("/exception /purecall"), _T("3 pure virtual call"), _T("3 pure virtual call")},
{_T("/exception /new"), _T("4 new operator fault"), _T("4 new operator fault")},
//{_T("/exception /security"), _T("5 security error"), _T("5 security error")},
{_T("/exception /invparam"), _T("6 invalid parameter"), _T("6 invalid parameter")},
{_T("/exception /sigabrt"), _T("7 SIGABRT signal"), _T("7 SIGABRT signal")},
{_T("/exception /sigfpe"), _T("8 SIGFPE signal"), _T("0 SEH exception")},
{_T("/exception /sigill"), _T("9 SIGILL signal"), _T("9 SIGILL signal")},
{_T("/exception /sigint"), _T("10 SIGINT signal"), _T("10 SIGINT signal")},
{_T("/exception /sigsegv"), _T("11 SIGSEGV signal"), _T("11 SIGSEGV signal")},
{_T("/exception /sigterm"), _T("12 SIGTERM signal"), _T("12 SIGTERM signal")},
{_T("/manual_report"), _T("0 SEH exception"), _T("0 SEH exception")}
};
int j;
for(j=0; j<2; j++)
{
int i;
for(i=0; i<PARAM_COUNT; i++)
{
if(j==0)
printf(".");
else
printf(",");
fflush(stdout);
// Create a temporary folder
CString sAppDataFolder;
Utility::GetSpecialFolder(CSIDL_APPDATA, sAppDataFolder);
sTmpFolder = sAppDataFolder+_T("\\CrashRptExceptionTest");
Utility::RecycleFile(sTmpFolder, TRUE); // remove folder if exists
BOOL bCreateFolder = Utility::CreateFolder(sTmpFolder);
strconv_t strconv;
TEST_ASSERT_MSG(bCreateFolder, "Error creating temp folder %s", strconv.t2a(sTmpFolder.GetBuffer(0)));
// Format command line
TCHAR szCmdLine[_MAX_PATH]=_T("");
_tcscat_s(szCmdLine, _MAX_PATH, _T("\""));
_tcscat_s(szCmdLine, _MAX_PATH, sExePath.GetBuffer(0));
_tcscat_s(szCmdLine, _MAX_PATH, _T("\" "));
_tcscat_s(szCmdLine, _MAX_PATH, aParams[i].szCmdLine);
if(j==1)
{
_tcscat_s(szCmdLine, _MAX_PATH, _T(" /exception_in_worker_thread"));
}
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
// Launch this executable with special params causing crash
BOOL bCreateProcess = CreateProcess(
sExePath, (LPWSTR)strconv.t2w(szCmdLine), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
TEST_ASSERT_MSG(bCreateProcess, "Error creating process %s", strconv.t2a(szCmdLine));
// Wait until process terminates
WaitForSingleObject(pi.hProcess, INFINITE);
int k;
for(k=0; k<50; k++)
{
// Wait some more time to let CrashRpt create error report file
Sleep(100);
// Look for crash report file
CFindFile ff;
BOOL bFind = ff.FindFile(sTmpFolder+_T("\\*.zip"));
if(!bFind)
continue;
// Try to open file
FILE* f = NULL;
_TFOPEN_S(f, ff.GetFileName(), _T("rb"));
if(f!=NULL)
{
fclose(f);
break;
}
}
{
// Look for crash report file
CFindFile ff;
BOOL bFind = ff.FindFile(sTmpFolder+_T("\\*.zip"));
TEST_ASSERT_MSG(bFind, "Could not find generated crash report file for exception type: %s", strconv.w2a(aParams[i].szExceptionType));
// Open crash report
CString sReportName = sTmpFolder + _T("\\");
sReportName += ff.m_fd.cFileName;
CrpHandle hReport;
int nOpenResult = crpOpenErrorReport(sReportName, NULL, NULL, 0, &hReport);
TEST_ASSERT_MSG(nOpenResult==0 && hReport!=0, "Error opening error report file %s", strconv.t2a(sReportName.GetBuffer(0)));
// Get exception type from report
const int BUFF_SIZE = 256;
TCHAR szBuffer[BUFF_SIZE];
int nResult = crpGetPropertyW(hReport, CRP_TBL_XMLDESC_MISC, CRP_COL_EXCEPTION_TYPE, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT_MSG(nResult==0, "Error getting property from error report");
int nCompareResult = _tcscmp(szBuffer, j==0?aParams[i].szExceptionType:aParams[i].szExceptionTypeInWorkerThread);
TEST_ASSERT_MSG(nCompareResult==0, "Invalid exception type: %s, while expected: %s", strconv.w2a(szBuffer), strconv.w2a(aParams[i].szExceptionType));
// Get exception thread ID
nResult = crpGetPropertyW(hReport, CRP_TBL_MDMP_MISC, CRP_COL_EXCEPTION_THREAD_ROWID, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT_MSG(nResult==0, "Error getting exception thread ID");
int nExceptionThreadRowId = _ttoi(szBuffer);
// Get exception thread's stack table ID
nResult = crpGetPropertyW(hReport, CRP_TBL_MDMP_THREADS, CRP_COL_THREAD_STACK_TABLEID, nExceptionThreadRowId, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT_MSG(nResult==0, "Error getting thread's stack table ID");
CString sStackTraceTableId = szBuffer;
#ifndef _WIN64
if(j==0)
{
if(i==0) // SEH
{
// Get stack frames
int nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT_MSG(nResult==0, "Error getting symbol name");
TEST_ASSERT(_tcscmp(szBuffer, _T("crEmulateCrash"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT_MSG(nResult==0, "Error getting symbol name");
TEST_ASSERT(_tcscmp(szBuffer, _T("wmain"))==0);
}
else if(i==1) // terminate
{
// Get stack frames
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::GenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::TerminateHandler"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 3, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("crEmulateCrash"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 4, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("wmain"))==0);
}
else if(i==2) // unexpected
{
// Get stack frames
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::GenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::UnexpectedHandler"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 3, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
#ifndef CRASHRPT_LIB
TEST_ASSERT(_tcscmp(szBuffer, _T("wmain"))==0);
#else
TEST_ASSERT(_tcscmp(szBuffer, _T("crEmulateCrash"))==0);
#endif
}
else if(i==3) // pure call
{
// Get stack frames
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::GenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::PureCallHandler"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 3, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
#ifndef CRASHRPT_LIB
TEST_ASSERT(_tcscmp(szBuffer, _T("CDerived::~CDerived"))==0);
#else
TEST_ASSERT(_tcscmp(szBuffer, _T("CBase::~CBase"))==0);
#endif
}
else if(i==13) // manual
{
// Get stack frames
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::GenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("crGenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 2, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("wmain"))==0);
}
}
else if(j==1)
{
if(i==0) // SEH
{
// Get stack frames
int nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("crEmulateCrash"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CrashThread"))==0);
}
else if(i==1) // terminate
{
// Get stack frames
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::GenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::TerminateHandler"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 3, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("crEmulateCrash"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 4, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CrashThread"))==0);
}
else if(i==13) // manual
{
// Get stack frames
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 0, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CCrashHandler::GenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 1, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("crGenerateErrorReport"))==0);
nResult = crpGetPropertyW(hReport, sStackTraceTableId, CRP_COL_STACK_SYMBOL_NAME, 2, szBuffer, BUFF_SIZE, NULL);
TEST_ASSERT(nResult==0);
TEST_ASSERT(_tcscmp(szBuffer, _T("CrashThread"))==0);
}
}
#endif //!_WIN64
// Close report
crpCloseErrorReport(hReport);
}
// Remove folder
Utility::RecycleFile(sTmpFolder, TRUE);
}
}
__TEST_CLEANUP__;
// Remove folder
Utility::RecycleFile(sTmpFolder, TRUE);
}
#endif