ReactOS 0.4.15-dev-7942-gd23573b
dbgrpt.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS CRT library
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Debug CRT reporting functions
5 * COPYRIGHT: Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8// This file should not be included in release builds,
9// but since we do not have a good mechanism for this at the moment,
10// just rely on the compiler to optimize it away instead of omitting the code.
11//#ifdef _DEBUG
12
13#include <crtdbg.h>
14#include <stdio.h>
15#include <signal.h>
16#include <windows.h>
17
18#undef OutputDebugString
19#undef _CrtSetReportMode
20#undef _CrtSetReportFile
21
22#define DBGRPT_MAX_BUFFER_SIZE 4096
23#define DBGRPT_ASSERT_PREFIX_MESSAGE "Assertion failed: "
24#define DBGRPT_ASSERT_PREFIX_NOMESSAGE "Assertion failed!"
25#define DBGRPT_STRING_TOO_LONG "_CrtDbgReport: String too long"
26
27// Keep track of active asserts
28static long _CrtInAssert = -1;
29// State per type
31{
35};
36// Caption per type
37static const wchar_t* _CrtModeMessages[_CRT_ERRCNT] =
38{
39 L"Warning",
40 L"Error",
41 L"Assertion Failed"
42};
43// Report files
45{
49};
50
51// Manually delay-load as to not have a dependency on user32
55
56template <typename char_t>
58
59template<>
61{
62 typedef char char_t;
63
64 static const wchar_t* szAssertionMessage;
65 static const char_t* szEmptyString;
66 static const char_t* szUnknownFile;
67
68 static void OutputDebugString(const char_t* message);
69 static size_t StringLength(const char_t* str) { return strlen(str); }
70};
71
72template<>
74{
75 typedef wchar_t char_t;
76
77 static const wchar_t* szAssertionMessage;
78 static const char_t* szEmptyString;
79 static const char_t* szUnknownFile;
80
81 static void OutputDebugString(const char_t* message);
82 static size_t StringLength(const char_t* str) { return wcslen(str); };
83};
84
85// Shortcut
88
90 L"Debug %s!\n"
91 L"%s%hs" /* module */
92 L"%s%hs" /* filename */
93 L"%s%s" /* linenumber */
94 L"%s%hs" /* message */
95 L"\n\n(Press Retry to debug the application)";
97 L"Debug %s!\n"
98 L"%s%ws" /* module */
99 L"%s%ws" /* filename */
100 L"%s%s" /* linenumber */
101 L"%s%ws" /* message */
102 L"\n\n(Press Retry to debug the application)";
103
106
107const achar_traits::char_t* achar_traits::szUnknownFile = "<unknown file>";
108const wchar_traits::char_t* wchar_traits::szUnknownFile = L"<unknown file>";
109
111{
113}
114
115inline void wchar_traits::OutputDebugString(const wchar_t* message)
116{
118}
119
120static
122{
123 if (_CrtUser32Handle == NULL)
124 {
125 HMODULE mod = LoadLibraryExW(L"user32.dll", NULL, 0 /* NT6+: LOAD_LIBRARY_SEARCH_SYSTEM32 */);
126 if (mod == NULL)
128
130 {
133 }
134 }
135
137}
138
140{
142
144 {
146 if (proc == NULL)
148
150 }
151
153}
154
155
156template <typename char_t>
157static int _CrtDbgReportWindow(int reportType, const char_t *filename, int linenumber, const char_t *moduleName, const char_t* message)
158{
159 typedef dbgrpt_char_traits<char_t> traits;
160
161 wchar_t szCompleteMessage[DBGRPT_MAX_BUFFER_SIZE] = {0};
162 wchar_t LineBuffer[20] = {0};
163
164 if (filename && !filename[0])
165 filename = NULL;
166 if (moduleName && !moduleName[0])
167 moduleName = NULL;
168 if (message && !message[0])
169 message = NULL;
170 if (linenumber)
171 _itow(linenumber, LineBuffer, 10);
172
173 _snwprintf(szCompleteMessage,
174 _countof(szCompleteMessage) - 1,
175 traits::szAssertionMessage,
176 _CrtModeMessages[reportType],
177 moduleName ? L"\nModule: " : L"", moduleName ? moduleName : traits::szEmptyString,
178 filename ? L"\nFile: " : L"", filename ? filename : traits::szEmptyString,
179 LineBuffer[0] ? L"\nLine: " : L"", LineBuffer[0] ? LineBuffer : L"",
180 message ? L"\n\n" : L"", message ? message : traits::szEmptyString);
181
182 if (IsDebuggerPresent())
183 {
184 OutputDebugStringW(szCompleteMessage);
185 }
186
187 tMessageBoxW messageBox = _CrtGetMessageBox();
188 if (!messageBox)
189 return (IsDebuggerPresent() ? IDRETRY : IDABORT);
190
191 // TODO: If we are not interacive, add MB_SERVICE_NOTIFICATION
192 return messageBox(NULL, szCompleteMessage, L"ReactOS C++ Runtime Library",
194}
195
196template <typename char_t>
197static int _CrtEnterDbgReport(int reportType, const char_t *filename, int linenumber)
198{
199 typedef dbgrpt_char_traits<char_t> traits;
200
201 if (reportType < 0 || reportType >= _CRT_ERRCNT)
202 return FALSE;
203
204 if (reportType == _CRT_ASSERT)
205 {
207 {
208 char LineBuffer[20] = {0};
209
210 _itoa(linenumber, LineBuffer, 10);
211
212 OutputDebugStringA("Nested Assert from File: ");
213 traits::OutputDebugString(filename ? filename : traits::szUnknownFile);
214 OutputDebugStringA(", Line: ");
215 OutputDebugStringA(LineBuffer);
216 OutputDebugStringA("\n");
217
218 _CrtDbgBreak();
219
221 return FALSE;
222 }
223 }
224 return TRUE;
225}
226
227static
228void _CrtLeaveDbgReport(int reportType)
229{
230 if (reportType == _CRT_ASSERT)
232}
233
235int __cdecl _CrtSetReportMode(int reportType, int reportMode)
236{
237 if (reportType >= _CRT_ERRCNT || reportType < 0)
238 return 0;
239
240 int oldReportMode = _CrtModeOutputFormat[reportType];
241 if (reportMode != _CRTDBG_REPORT_MODE)
242 _CrtModeOutputFormat[reportType] = reportMode;
243 return oldReportMode;
244}
245
247_HFILE __cdecl _CrtSetReportFile(int reportType, _HFILE reportFile)
248{
249 if (reportType >= _CRT_ERRCNT || reportType < 0)
250 return NULL;
251
252 _HFILE oldReportFile = _CrtReportFiles[reportType];
253 if (reportFile != _CRTDBG_REPORT_FILE)
254 _CrtReportFiles[reportType] = reportFile;
255 return oldReportFile;
256}
257
258template <typename char_t>
259static inline BOOL _CrtDbgReportToFile(HANDLE hFile, const char_t* szMsg)
260{
261 typedef dbgrpt_char_traits<char_t> traits;
262
264 return FALSE;
265
268 else if (hFile == _CRTDBG_FILE_STDERR)
270
271 DWORD cbMsg = (DWORD)(traits::StringLength(szMsg) * sizeof(char_t));
272 return ::WriteFile(hFile, szMsg, cbMsg, &cbMsg, NULL);
273}
274
275template <typename char_t>
276static int _CrtHandleDbgReport(int reportType, const char_t* szCompleteMessage, const char_t* szFormatted,
277 const char_t *filename, int linenumber, const char_t *moduleName)
278{
279 typedef dbgrpt_char_traits<char_t> traits;
280
281 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_FILE)
282 {
283 _CrtDbgReportToFile<char_t>(_CrtReportFiles[reportType], szCompleteMessage);
284 }
285
287 {
288 traits::OutputDebugString(szCompleteMessage);
289 }
290
291 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_WNDW)
292 {
293 int nResult = _CrtDbgReportWindow(reportType, filename, linenumber, moduleName, szFormatted);
294 switch (nResult)
295 {
296 case IDRETRY:
297 return TRUE;
298 case IDIGNORE:
299 default:
300 return FALSE;
301 case IDABORT:
302 raise(SIGABRT);
303 _exit(3);
304 return FALSE; // Unreachable
305 }
306 }
307
308 return FALSE;
309}
310
311
313int __cdecl
315 int reportType,
316 const char *filename,
317 int linenumber,
318 const char *moduleName,
319 const char *format,
321{
322 char szFormatted[DBGRPT_MAX_BUFFER_SIZE] = {0}; // The user provided message
323 char szCompleteMessage[DBGRPT_MAX_BUFFER_SIZE] = {0}; // The output for debug / file
324
325 // Check for recursive _CrtDbgReport calls, and validate reportType
326 if (!_CrtEnterDbgReport(reportType, filename, linenumber))
327 return -1;
328
329 if (filename)
330 {
331 _snprintf(szCompleteMessage,
332 _countof(szCompleteMessage) - 1,
333 "%s(%d) : ",
334 filename,
335 linenumber);
336 }
337
338 if (format)
339 {
340 int len = _vsnprintf(szFormatted,
342 format,
343 arglist);
344 if (len < 0)
345 {
346 strcpy(szFormatted, DBGRPT_STRING_TOO_LONG);
347 }
348
349 if (reportType == _CRT_ASSERT)
350 strcat(szCompleteMessage, DBGRPT_ASSERT_PREFIX_MESSAGE);
351 strcat(szCompleteMessage, szFormatted);
352 }
353 else if (reportType == _CRT_ASSERT)
354 {
355 strcat(szCompleteMessage, DBGRPT_ASSERT_PREFIX_NOMESSAGE);
356 }
357
358 if (reportType == _CRT_ASSERT)
359 {
360 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_FILE)
361 strcat(szCompleteMessage, "\r");
362 strcat(szCompleteMessage, "\n");
363 }
364
365 // FIXME: Handle user report hooks here
366
367 int nResult = _CrtHandleDbgReport(reportType, szCompleteMessage, szFormatted, filename, linenumber, moduleName);
368
369 _CrtLeaveDbgReport(reportType);
370
371 return nResult;
372}
373
375int __cdecl
377 int reportType,
378 const wchar_t *filename,
379 int linenumber,
380 const wchar_t *moduleName,
381 const wchar_t *format,
383{
384 wchar_t szFormatted[DBGRPT_MAX_BUFFER_SIZE] = {0}; // The user provided message
385 wchar_t szCompleteMessage[DBGRPT_MAX_BUFFER_SIZE] = {0}; // The output for debug / file
386
387 // Check for recursive _CrtDbgReportW calls, and validate reportType
388 if (!_CrtEnterDbgReport(reportType, filename, linenumber))
389 return -1;
390
391 if (filename)
392 {
393 _snwprintf(szCompleteMessage,
394 _countof(szCompleteMessage) - 1,
395 L"%s(%d) : ",
396 filename,
397 linenumber);
398 }
399
400 if (format)
401 {
402 int len = _vsnwprintf(szFormatted,
404 format,
405 arglist);
406 if (len < 0)
407 {
409 }
410
411 if (reportType == _CRT_ASSERT)
412 wcscat(szCompleteMessage, _CRT_WIDE(DBGRPT_ASSERT_PREFIX_MESSAGE));
413 wcscat(szCompleteMessage, szFormatted);
414 }
415 else if (reportType == _CRT_ASSERT)
416 {
418 }
419
420 if (reportType == _CRT_ASSERT)
421 {
422 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_FILE)
423 wcscat(szCompleteMessage, L"\r");
424 wcscat(szCompleteMessage, L"\n");
425 }
426
427 // FIXME: Handle user report hooks here
428
429 int nResult = _CrtHandleDbgReport(reportType, szCompleteMessage, szFormatted, filename, linenumber, moduleName);
430
431 _CrtLeaveDbgReport(reportType);
432
433 return nResult;
434}
435
437int __cdecl
439 int reportType,
440 const char *filename,
441 int linenumber,
442 const char *moduleName,
443 const char *format,
445{
446 return _VCrtDbgReportA(reportType, filename, linenumber, moduleName, format, arglist);
447}
448
450int __cdecl
452 int reportType,
453 const wchar_t *filename,
454 int linenumber,
455 const wchar_t *moduleName,
456 const wchar_t *format,
458{
459 return _VCrtDbgReportW(reportType, filename, linenumber, moduleName, format, arglist);
460}
461
463int __cdecl
465 int reportType,
466 const char *filename,
467 int linenumber,
468 const char *moduleName,
469 const char *format,
470 ...)
471{
473 int result;
474
476 result = _VCrtDbgReportA(reportType, filename, linenumber, moduleName, format, arglist);
478 return result;
479}
480
482int __cdecl
484 int reportType,
485 const wchar_t *filename,
486 int linenumber,
487 const wchar_t *moduleName,
488 const wchar_t *format,
489 ...)
490{
492 int result;
493
495 result = _VCrtDbgReportW(reportType, filename, linenumber, moduleName, format, arglist);
497 return result;
498}
499
500//#endif // _DEBUG
void _exit(int exitcode)
Definition: _exit.c:25
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define __cdecl
Definition: accygwin.h:79
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
HWND hWnd
Definition: settings.c:17
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
#define EXTERN_C
Definition: basetyps.h:12
int __cdecl raise(int _SigNum)
Definition: signal.c:71
#define SIGABRT
Definition: signal.h:28
#define _CRTDBG_MODE_DEBUG
Definition: crtdbg.h:25
#define _CRT_ASSERT
Definition: crtdbg.h:21
#define _CRTDBG_FILE_STDOUT
Definition: crtdbg.h:31
#define _CRTDBG_MODE_WNDW
Definition: crtdbg.h:26
#define _CRTDBG_MODE_FILE
Definition: crtdbg.h:24
#define _CRTDBG_REPORT_MODE
Definition: crtdbg.h:27
#define _CrtSetReportMode(t, f)
Definition: crtdbg.h:129
#define _CRTDBG_FILE_STDERR
Definition: crtdbg.h:32
#define _CRTDBG_INVALID_HFILE
Definition: crtdbg.h:29
#define _CRT_ERRCNT
Definition: crtdbg.h:22
#define _CrtDbgBreak()
Definition: crtdbg.h:102
#define _CRTDBG_REPORT_FILE
Definition: crtdbg.h:33
#define _CrtSetReportFile(t, f)
Definition: crtdbg.h:130
unsigned short wchar_t
Definition: crtdefs.h:345
#define _CRT_WIDE(_String)
Definition: crtdefs.h:55
static _HFILE _CrtReportFiles[_CRT_ERRCNT]
Definition: dbgrpt.cpp:44
static HMODULE _CrtUser32Handle
Definition: dbgrpt.cpp:53
static BOOL _CrtDbgReportToFile(HANDLE hFile, const char_t *szMsg)
Definition: dbgrpt.cpp:259
EXTERN_C int __cdecl _VCrtDbgReportA(int reportType, const char *filename, int linenumber, const char *moduleName, const char *format, va_list arglist)
Definition: dbgrpt.cpp:314
#define DBGRPT_MAX_BUFFER_SIZE
Definition: dbgrpt.cpp:22
EXTERN_C int __cdecl _CrtDbgReportWV(int reportType, const wchar_t *filename, int linenumber, const wchar_t *moduleName, const wchar_t *format, va_list arglist)
Definition: dbgrpt.cpp:451
static void _CrtLeaveDbgReport(int reportType)
Definition: dbgrpt.cpp:228
EXTERN_C int __cdecl _VCrtDbgReportW(int reportType, const wchar_t *filename, int linenumber, const wchar_t *moduleName, const wchar_t *format, va_list arglist)
Definition: dbgrpt.cpp:376
EXTERN_C int __cdecl _CrtDbgReportV(int reportType, const char *filename, int linenumber, const char *moduleName, const char *format, va_list arglist)
Definition: dbgrpt.cpp:438
dbgrpt_char_traits< wchar_t > wchar_traits
Definition: dbgrpt.cpp:87
EXTERN_C int __cdecl _CrtDbgReportW(int reportType, const wchar_t *filename, int linenumber, const wchar_t *moduleName, const wchar_t *format,...)
Definition: dbgrpt.cpp:483
static int _CrtHandleDbgReport(int reportType, const char_t *szCompleteMessage, const char_t *szFormatted, const char_t *filename, int linenumber, const char_t *moduleName)
Definition: dbgrpt.cpp:276
int(WINAPI * tMessageBoxW)(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
Definition: dbgrpt.cpp:52
#define DBGRPT_STRING_TOO_LONG
Definition: dbgrpt.cpp:25
static int _CrtEnterDbgReport(int reportType, const char_t *filename, int linenumber)
Definition: dbgrpt.cpp:197
static tMessageBoxW _CrtGetMessageBox()
Definition: dbgrpt.cpp:139
EXTERN_C int __cdecl _CrtDbgReport(int reportType, const char *filename, int linenumber, const char *moduleName, const char *format,...)
Definition: dbgrpt.cpp:464
static tMessageBoxW _CrtMessageBoxW
Definition: dbgrpt.cpp:54
dbgrpt_char_traits< char > achar_traits
Definition: dbgrpt.cpp:86
static int _CrtDbgReportWindow(int reportType, const char_t *filename, int linenumber, const char_t *moduleName, const char_t *message)
Definition: dbgrpt.cpp:157
#define DBGRPT_ASSERT_PREFIX_MESSAGE
Definition: dbgrpt.cpp:23
#define DBGRPT_ASSERT_PREFIX_NOMESSAGE
Definition: dbgrpt.cpp:24
static int _CrtModeOutputFormat[_CRT_ERRCNT]
Definition: dbgrpt.cpp:30
static const wchar_t * _CrtModeMessages[_CRT_ERRCNT]
Definition: dbgrpt.cpp:37
static long _CrtInAssert
Definition: dbgrpt.cpp:28
static HMODULE _CrtGetUser32()
Definition: dbgrpt.cpp:121
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define GetProcAddress(x, y)
Definition: compat.h:753
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define FreeLibrary(x)
Definition: compat.h:748
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
Definition: loader.c:288
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned char
Definition: typeof.h:29
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLenum GLsizei len
Definition: glext.h:6722
GLuint64EXT * result
Definition: glext.h:11304
static int mod
Definition: i386-dis.c:1288
void WINAPI SHIM_OBJ_NAME() OutputDebugStringA(LPCSTR lpOutputString)
Definition: ignoredbgout.c:18
void WINAPI SHIM_OBJ_NAME() OutputDebugStringW(LPCWSTR lpOutputString)
Definition: ignoredbgout.c:23
_CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest, size_t _Count, const wchar_t *_Format, va_list _Args)
_CRTIMP char *__cdecl _itoa(_In_ int _Value, _Pre_notnull_ _Post_z_ char *_Dest, _In_ int _Radix)
_CRTIMP wchar_t *__cdecl _itow(_In_ int _Value, _Pre_notnull_ _Post_z_ wchar_t *_Dest, _In_ int _Radix)
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
void * _InterlockedCompareExchangePointer(_Interlocked_operand_ void *volatile *_Destination, void *_Exchange, void *_Comparand)
long __cdecl _InterlockedIncrement(_Interlocked_operand_ long volatile *_Addend)
long __cdecl _InterlockedDecrement(_Interlocked_operand_ long volatile *_Addend)
const char * filename
Definition: ioapi.h:137
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format,...)
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
_In_ HANDLE hFile
Definition: mswsock.h:90
unsigned int UINT
Definition: ndis.h:50
#define DWORD
Definition: nt_native.h:44
#define L(x)
Definition: ntvdm.h:50
static HANDLE proc()
Definition: pdb.c:34
const WCHAR * str
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
va_lists_t arglist[FMT_ARGMAX+1]
Definition: format.c:284
#define _countof(array)
Definition: sndvol32.h:68
static const char_t * szUnknownFile
Definition: dbgrpt.cpp:66
static void OutputDebugString(const char_t *message)
Definition: dbgrpt.cpp:110
static size_t StringLength(const char_t *str)
Definition: dbgrpt.cpp:69
static const wchar_t * szAssertionMessage
Definition: dbgrpt.cpp:64
static const char_t * szEmptyString
Definition: dbgrpt.cpp:65
static void OutputDebugString(const char_t *message)
Definition: dbgrpt.cpp:115
static const char_t * szEmptyString
Definition: dbgrpt.cpp:78
static const wchar_t * szAssertionMessage
Definition: dbgrpt.cpp:77
static size_t StringLength(const char_t *str)
Definition: dbgrpt.cpp:82
static const char_t * szUnknownFile
Definition: dbgrpt.cpp:79
Definition: tftpd.h:60
HANDLE HMODULE
Definition: typedefs.h:77
#define STD_OUTPUT_HANDLE
Definition: winbase.h:268
#define STD_ERROR_HANDLE
Definition: winbase.h:269
#define OutputDebugString
Definition: winbase.h:3890
BOOL WINAPI IsDebuggerPresent(void)
Definition: debugger.c:580
#define WINAPI
Definition: msvc.h:6
#define MB_SETFOREGROUND
Definition: winuser.h:814
#define MB_ICONHAND
Definition: winuser.h:788
#define MB_TASKMODAL
Definition: winuser.h:816
#define IDIGNORE
Definition: winuser.h:834
#define MB_ABORTRETRYIGNORE
Definition: winuser.h:791
#define IDABORT
Definition: winuser.h:832
#define IDRETRY
Definition: winuser.h:833
#define _vsnprintf
Definition: xmlstorage.h:202
#define _snprintf
Definition: xmlstorage.h:200
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185