ReactOS 0.4.15-dev-6068-g8061a6f
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
20#define DBGRPT_MAX_BUFFER_SIZE 4096
21#define DBGRPT_ASSERT_PREFIX_MESSAGE "Assertion failed: "
22#define DBGRPT_ASSERT_PREFIX_NOMESSAGE "Assertion failed!"
23#define DBGRPT_STRING_TOO_LONG "_CrtDbgReport: String too long"
24
25// Keep track of active asserts
26static long _CrtInAssert = -1;
27// State per type
29{
33};
34// Caption per type
35static const wchar_t* _CrtModeMessages[_CRT_ERRCNT] =
36{
37 L"Warning",
38 L"Error",
39 L"Assertion Failed"
40};
41
42// Manually delay-load as to not have a dependency on user32
46
47template <typename char_t>
49
50template<>
52{
53 typedef char char_t;
54
55 static const wchar_t* szAssertionMessage;
56 static const char_t* szEmptyString;
57 static const char_t* szUnknownFile;
58
59 static void OutputDebugString(const char_t* message);
60};
61
62template<>
64{
65 typedef wchar_t char_t;
66
67 static const wchar_t* szAssertionMessage;
68 static const char_t* szEmptyString;
69 static const char_t* szUnknownFile;
70
71 static void OutputDebugString(const char_t* message);
72};
73
74// Shortcut
77
78
80 L"Debug %s!\n"
81 L"%s%hs" /* module */
82 L"%s%hs" /* filename */
83 L"%s%s" /* linenumber */
84 L"%s%hs" /* message */
85 L"\n\n(Press Retry to debug the application)";
87 L"Debug %s!\n"
88 L"%s%ws" /* module */
89 L"%s%ws" /* filename */
90 L"%s%s" /* linenumber */
91 L"%s%ws" /* message */
92 L"\n\n(Press Retry to debug the application)";
93
96
99
101{
103}
104
106{
108}
109
110
111static
113{
114 if (_CrtUser32Handle == NULL)
115 {
116 HMODULE mod = LoadLibraryExW(L"user32.dll", NULL, 0 /* NT6+: LOAD_LIBRARY_SEARCH_SYSTEM32 */);
117 if (mod == NULL)
119
121 {
124 }
125 }
126
128}
129
131{
133
135 {
137 if (proc == NULL)
139
141 }
142
144}
145
146
147template <typename char_t>
148static int _CrtDbgReportWindow(int reportType, const char_t *filename, int linenumber, const char_t *moduleName, const char_t* message)
149{
150 typedef dbgrpt_char_traits<char_t> traits;
151
152 wchar_t szCompleteMessage[(DBGRPT_MAX_BUFFER_SIZE+1)*2] = {0};
153 wchar_t LineBuffer[20] = {0};
154
155 if (filename && !filename[0])
156 filename = NULL;
157 if (moduleName && !moduleName[0])
158 moduleName = NULL;
159 if (message && !message[0])
160 message = NULL;
161 if (linenumber)
162 _itow(linenumber, LineBuffer, 10);
163
164 _snwprintf(szCompleteMessage, DBGRPT_MAX_BUFFER_SIZE * 2,
165 traits::szAssertionMessage,
166 _CrtModeMessages[reportType],
167 moduleName ? L"\nModule: " : L"", moduleName ? moduleName : traits::szEmptyString,
168 filename ? L"\nFile: " : L"", filename ? filename : traits::szEmptyString,
169 LineBuffer[0] ? L"\nLine: " : L"", LineBuffer[0] ? LineBuffer : L"",
170 message ? L"\n\n" : L"", message ? message : traits::szEmptyString);
171
172 if (IsDebuggerPresent())
173 {
174 OutputDebugStringW(szCompleteMessage);
175 }
176
177 tMessageBoxW messageBox = _CrtGetMessageBox();
178 if (!messageBox)
179 return IsDebuggerPresent() ? IDRETRY : IDABORT;
180
181 // TODO: If we are not interacive, add MB_SERVICE_NOTIFICATION
182 return messageBox(NULL, szCompleteMessage, L"ReactOS C++ Runtime Library",
184}
185
186template <typename char_t>
187static int _CrtEnterDbgReport(int reportType, const char_t *filename, int linenumber)
188{
189 typedef dbgrpt_char_traits<char_t> traits;
190
191 if (reportType < 0 || reportType >= _CRT_ERRCNT)
192 return FALSE;
193
194 if (reportType == _CRT_ASSERT)
195 {
197 {
198 char LineBuffer[20] = {0};
199
200 _itoa(linenumber, LineBuffer, 10);
201
202 OutputDebugStringA("Nested Assert from File: ");
203 traits::OutputDebugString(filename ? filename : traits::szUnknownFile);
204 OutputDebugStringA(", Line: ");
205 OutputDebugStringA(LineBuffer);
206 OutputDebugStringA("\n");
207
208 _CrtDbgBreak();
209
211 return FALSE;
212 }
213 }
214 return TRUE;
215}
216
217static
218void _CrtLeaveDbgReport(int reportType)
219{
220 if (reportType == _CRT_ASSERT)
222}
223
224
225template <typename char_t>
226static int _CrtHandleDbgReport(int reportType, const char_t* szCompleteMessage, const char_t* szFormatted,
227 const char_t *filename, int linenumber, const char_t *moduleName)
228{
229 typedef dbgrpt_char_traits<char_t> traits;
230
231 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_FILE)
232 {
233 OutputDebugStringA("ERROR: Please implement _CrtSetReportFile first\n");
234 _CrtDbgBreak();
235 }
236
238 {
239 traits::OutputDebugString(szCompleteMessage);
240 }
241
242 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_WNDW)
243 {
244 int nResult = _CrtDbgReportWindow(reportType, filename, linenumber, moduleName, szFormatted);
245 switch (nResult)
246 {
247 case IDRETRY:
248 return TRUE;
249 case IDIGNORE:
250 default:
251 return FALSE;
252 case IDABORT:
253 raise(SIGABRT);
254 _exit(3);
255 return FALSE; // Unreachable
256 }
257 }
258
259 return FALSE;
260}
261
262
264int __cdecl _CrtDbgReport(int reportType, const char *filename, int linenumber, const char *moduleName, const char *format, ...)
265{
266 char szFormatted[DBGRPT_MAX_BUFFER_SIZE+1] = {0}; // The user provided message
267 char szCompleteMessage[(DBGRPT_MAX_BUFFER_SIZE+1)*2] = {0}; // The output for debug / file
268
269 // Check for recursive _CrtDbgReport calls, and validate reportType
270 if (!_CrtEnterDbgReport(reportType, filename, linenumber))
271 return -1;
272
273 if (filename)
274 {
275 _snprintf(szCompleteMessage, DBGRPT_MAX_BUFFER_SIZE, "%s(%d) : ", filename, linenumber);
276 }
277
278 if (format)
279 {
284
285 if (len < 0)
286 {
287 strcpy(szFormatted, DBGRPT_STRING_TOO_LONG);
288 }
289
290 if (reportType == _CRT_ASSERT)
291 strcat(szCompleteMessage, DBGRPT_ASSERT_PREFIX_MESSAGE);
292 strcat(szCompleteMessage, szFormatted);
293 }
294 else if (reportType == _CRT_ASSERT)
295 {
296 strcat(szCompleteMessage, DBGRPT_ASSERT_PREFIX_NOMESSAGE);
297 }
298
299 if (reportType == _CRT_ASSERT)
300 {
301 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_FILE)
302 strcat(szCompleteMessage, "\r");
303 strcat(szCompleteMessage, "\n");
304 }
305
306 // FIXME: Handle user report hooks here
307
308 int nResult = _CrtHandleDbgReport(reportType, szCompleteMessage, szFormatted, filename, linenumber, moduleName);
309
310 _CrtLeaveDbgReport(reportType);
311
312 return nResult;
313}
314
316int __cdecl _CrtDbgReportW(int reportType, const wchar_t *filename, int linenumber, const wchar_t *moduleName, const wchar_t *format, ...)
317{
318 wchar_t szFormatted[DBGRPT_MAX_BUFFER_SIZE+1] = {0}; // The user provided message
319 wchar_t szCompleteMessage[(DBGRPT_MAX_BUFFER_SIZE+1)*2] = {0}; // The output for debug / file
320
321 // Check for recursive _CrtDbgReportW calls, and validate reportType
322 if (!_CrtEnterDbgReport(reportType, filename, linenumber))
323 return -1;
324
325 if (filename)
326 {
327 _snwprintf(szCompleteMessage, DBGRPT_MAX_BUFFER_SIZE, L"%s(%d) : ", filename, linenumber);
328 }
329
330 if (format)
331 {
336
337 if (len < 0)
338 {
340 }
341
342 if (reportType == _CRT_ASSERT)
343 wcscat(szCompleteMessage, _CRT_WIDE(DBGRPT_ASSERT_PREFIX_MESSAGE));
344 wcscat(szCompleteMessage, szFormatted);
345 }
346 else if (reportType == _CRT_ASSERT)
347 {
349 }
350
351 if (reportType == _CRT_ASSERT)
352 {
353 if (_CrtModeOutputFormat[reportType] & _CRTDBG_MODE_FILE)
354 wcscat(szCompleteMessage, L"\r");
355 wcscat(szCompleteMessage, L"\n");
356 }
357
358 // FIXME: Handle user report hooks here
359
360 int nResult = _CrtHandleDbgReport(reportType, szCompleteMessage, szFormatted, filename, linenumber, moduleName);
361
362 _CrtLeaveDbgReport(reportType);
363
364 return nResult;
365}
366
367
368//#endif // _DEBUG
void _exit(int exitcode)
Definition: _exit.c:25
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
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
#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_MODE_WNDW
Definition: crtdbg.h:26
#define _CRTDBG_MODE_FILE
Definition: crtdbg.h:24
#define _CRT_ERRCNT
Definition: crtdbg.h:22
#define _CrtDbgBreak()
Definition: crtdbg.h:100
unsigned short wchar_t
Definition: crtdefs.h:345
#define _CRT_WIDE(_String)
Definition: crtdefs.h:55
static HMODULE _CrtUser32Handle
Definition: dbgrpt.cpp:44
#define DBGRPT_MAX_BUFFER_SIZE
Definition: dbgrpt.cpp:20
static void _CrtLeaveDbgReport(int reportType)
Definition: dbgrpt.cpp:218
dbgrpt_char_traits< wchar_t > wchar_traits
Definition: dbgrpt.cpp:76
EXTERN_C int __cdecl _CrtDbgReportW(int reportType, const wchar_t *filename, int linenumber, const wchar_t *moduleName, const wchar_t *format,...)
Definition: dbgrpt.cpp:316
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:226
int(WINAPI * tMessageBoxW)(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
Definition: dbgrpt.cpp:43
#define DBGRPT_STRING_TOO_LONG
Definition: dbgrpt.cpp:23
static int _CrtEnterDbgReport(int reportType, const char_t *filename, int linenumber)
Definition: dbgrpt.cpp:187
static tMessageBoxW _CrtGetMessageBox()
Definition: dbgrpt.cpp:130
EXTERN_C int __cdecl _CrtDbgReport(int reportType, const char *filename, int linenumber, const char *moduleName, const char *format,...)
Definition: dbgrpt.cpp:264
static tMessageBoxW _CrtMessageBoxW
Definition: dbgrpt.cpp:45
dbgrpt_char_traits< char > achar_traits
Definition: dbgrpt.cpp:75
static int _CrtDbgReportWindow(int reportType, const char_t *filename, int linenumber, const char_t *moduleName, const char_t *message)
Definition: dbgrpt.cpp:148
#define DBGRPT_ASSERT_PREFIX_MESSAGE
Definition: dbgrpt.cpp:21
#define DBGRPT_ASSERT_PREFIX_NOMESSAGE
Definition: dbgrpt.cpp:22
static int _CrtModeOutputFormat[_CRT_ERRCNT]
Definition: dbgrpt.cpp:28
static const wchar_t * _CrtModeMessages[_CRT_ERRCNT]
Definition: dbgrpt.cpp:35
static long _CrtInAssert
Definition: dbgrpt.cpp:26
static HMODULE _CrtGetUser32()
Definition: dbgrpt.cpp:112
#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
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLenum GLsizei len
Definition: glext.h:6722
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)
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
unsigned int UINT
Definition: ndis.h:50
#define L(x)
Definition: ntvdm.h:50
static HANDLE proc()
Definition: pdb.c:34
_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
static const char_t * szUnknownFile
Definition: dbgrpt.cpp:57
static void OutputDebugString(const char_t *message)
Definition: dbgrpt.cpp:100
static const wchar_t * szAssertionMessage
Definition: dbgrpt.cpp:55
static const char_t * szEmptyString
Definition: dbgrpt.cpp:56
static void OutputDebugString(const char_t *message)
Definition: dbgrpt.cpp:105
static const char_t * szEmptyString
Definition: dbgrpt.cpp:68
static const wchar_t * szAssertionMessage
Definition: dbgrpt.cpp:67
static const char_t * szUnknownFile
Definition: dbgrpt.cpp:69
Definition: tftpd.h:60
HANDLE HMODULE
Definition: typedefs.h:77
#define OutputDebugString
Definition: winbase.h:3761
BOOL WINAPI IsDebuggerPresent(void)
Definition: debugger.c:580
#define WINAPI
Definition: msvc.h:6
#define MB_SETFOREGROUND
Definition: winuser.h:808
#define MB_ICONHAND
Definition: winuser.h:782
#define MB_TASKMODAL
Definition: winuser.h:810
#define IDIGNORE
Definition: winuser.h:828
#define MB_ABORTRETRYIGNORE
Definition: winuser.h:785
#define IDABORT
Definition: winuser.h:826
#define IDRETRY
Definition: winuser.h:827
#define _vsnprintf
Definition: xmlstorage.h:202
#define _snprintf
Definition: xmlstorage.h:200
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185