1*04e0dc4aSTimo Kreuzer /***
2*04e0dc4aSTimo Kreuzer *report_runtime_error.cpp - startup error messages
3*04e0dc4aSTimo Kreuzer *
4*04e0dc4aSTimo Kreuzer * Copyright (c) Microsoft Corporation. All rights reserved.
5*04e0dc4aSTimo Kreuzer *
6*04e0dc4aSTimo Kreuzer *Purpose:
7*04e0dc4aSTimo Kreuzer * Prints out banner for runtime error messages.
8*04e0dc4aSTimo Kreuzer *
9*04e0dc4aSTimo Kreuzer *******************************************************************************/
10*04e0dc4aSTimo Kreuzer
11*04e0dc4aSTimo Kreuzer #include <corecrt_internal.h>
12*04e0dc4aSTimo Kreuzer #include <stdlib.h>
13*04e0dc4aSTimo Kreuzer
14*04e0dc4aSTimo Kreuzer
15*04e0dc4aSTimo Kreuzer
16*04e0dc4aSTimo Kreuzer // This is used during the expansion of the runtime error text.
17*04e0dc4aSTimo Kreuzer #define EOL L"\r\n"
18*04e0dc4aSTimo Kreuzer
issue_debug_notification(wchar_t const * const message)19*04e0dc4aSTimo Kreuzer static bool __cdecl issue_debug_notification(wchar_t const* const message) throw()
20*04e0dc4aSTimo Kreuzer {
21*04e0dc4aSTimo Kreuzer // This is referenced only in the Debug CRT build
22*04e0dc4aSTimo Kreuzer UNREFERENCED_PARAMETER(message);
23*04e0dc4aSTimo Kreuzer
24*04e0dc4aSTimo Kreuzer #ifdef _DEBUG
25*04e0dc4aSTimo Kreuzer switch (_CrtDbgReportW(_CRT_ERROR, nullptr, 0, nullptr, L"%ls", message))
26*04e0dc4aSTimo Kreuzer {
27*04e0dc4aSTimo Kreuzer case 1:
28*04e0dc4aSTimo Kreuzer _CrtDbgBreak();
29*04e0dc4aSTimo Kreuzer return true;
30*04e0dc4aSTimo Kreuzer
31*04e0dc4aSTimo Kreuzer case 0:
32*04e0dc4aSTimo Kreuzer return true;
33*04e0dc4aSTimo Kreuzer }
34*04e0dc4aSTimo Kreuzer #endif // _DEBUG
35*04e0dc4aSTimo Kreuzer
36*04e0dc4aSTimo Kreuzer return false;
37*04e0dc4aSTimo Kreuzer }
38*04e0dc4aSTimo Kreuzer
39*04e0dc4aSTimo Kreuzer
40*04e0dc4aSTimo Kreuzer
41*04e0dc4aSTimo Kreuzer
42*04e0dc4aSTimo Kreuzer // Enclaves do not support error messages outside of OutputDebugString.
43*04e0dc4aSTimo Kreuzer #ifdef _UCRT_ENCLAVE_BUILD
44*04e0dc4aSTimo Kreuzer
__acrt_report_runtime_error(wchar_t const * const message)45*04e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_report_runtime_error(wchar_t const* const message)
46*04e0dc4aSTimo Kreuzer {
47*04e0dc4aSTimo Kreuzer // Report the error using the debug
48*04e0dc4aSTimo Kreuzer issue_debug_notification(message);
49*04e0dc4aSTimo Kreuzer }
50*04e0dc4aSTimo Kreuzer
51*04e0dc4aSTimo Kreuzer #else /* ^^^ _UCRT_ENCLAVE_BUILD ^^^ // vvv !_UCRT_ENCLAVE_BUILD vvv */
52*04e0dc4aSTimo Kreuzer
53*04e0dc4aSTimo Kreuzer /*
54*04e0dc4aSTimo Kreuzer * __acrt_app_type, together with __error_mode, determine how error messages
55*04e0dc4aSTimo Kreuzer * are written out.
56*04e0dc4aSTimo Kreuzer */
57*04e0dc4aSTimo Kreuzer static _crt_app_type __acrt_app_type = _crt_unknown_app;
58*04e0dc4aSTimo Kreuzer
59*04e0dc4aSTimo Kreuzer /***
60*04e0dc4aSTimo Kreuzer *void _set_app_type(int apptype) - interface to change __acrt_app_type
61*04e0dc4aSTimo Kreuzer *
62*04e0dc4aSTimo Kreuzer *Purpose:
63*04e0dc4aSTimo Kreuzer * Set, or change, the value of __acrt_app_type.
64*04e0dc4aSTimo Kreuzer *
65*04e0dc4aSTimo Kreuzer * Set the default debug lib report destination for console apps.
66*04e0dc4aSTimo Kreuzer *
67*04e0dc4aSTimo Kreuzer * This function is for INTERNAL USE ONLY.
68*04e0dc4aSTimo Kreuzer *
69*04e0dc4aSTimo Kreuzer *Entry:
70*04e0dc4aSTimo Kreuzer * int modeval = _crt_unknown_app, unknown
71*04e0dc4aSTimo Kreuzer * _crt_console_app, console, or command line, application
72*04e0dc4aSTimo Kreuzer * _crt_gui_app, GUI, or Windows, application
73*04e0dc4aSTimo Kreuzer *
74*04e0dc4aSTimo Kreuzer *Exit:
75*04e0dc4aSTimo Kreuzer *
76*04e0dc4aSTimo Kreuzer *Exceptions:
77*04e0dc4aSTimo Kreuzer *
78*04e0dc4aSTimo Kreuzer *******************************************************************************/
79*04e0dc4aSTimo Kreuzer
_set_app_type(_crt_app_type const new_app_type)80*04e0dc4aSTimo Kreuzer extern "C" void __cdecl _set_app_type(_crt_app_type const new_app_type)
81*04e0dc4aSTimo Kreuzer {
82*04e0dc4aSTimo Kreuzer __acrt_app_type = new_app_type;
83*04e0dc4aSTimo Kreuzer }
84*04e0dc4aSTimo Kreuzer
_query_app_type()85*04e0dc4aSTimo Kreuzer extern "C" _crt_app_type __cdecl _query_app_type()
86*04e0dc4aSTimo Kreuzer {
87*04e0dc4aSTimo Kreuzer return __acrt_app_type;
88*04e0dc4aSTimo Kreuzer }
89*04e0dc4aSTimo Kreuzer
90*04e0dc4aSTimo Kreuzer
91*04e0dc4aSTimo Kreuzer
should_write_error_to_console()92*04e0dc4aSTimo Kreuzer static bool __cdecl should_write_error_to_console() throw()
93*04e0dc4aSTimo Kreuzer {
94*04e0dc4aSTimo Kreuzer int const error_mode = _set_error_mode(_REPORT_ERRMODE);
95*04e0dc4aSTimo Kreuzer
96*04e0dc4aSTimo Kreuzer if (error_mode == _OUT_TO_STDERR)
97*04e0dc4aSTimo Kreuzer {
98*04e0dc4aSTimo Kreuzer return true;
99*04e0dc4aSTimo Kreuzer }
100*04e0dc4aSTimo Kreuzer
101*04e0dc4aSTimo Kreuzer if (error_mode == _OUT_TO_DEFAULT && __acrt_app_type == _crt_console_app)
102*04e0dc4aSTimo Kreuzer {
103*04e0dc4aSTimo Kreuzer return true;
104*04e0dc4aSTimo Kreuzer }
105*04e0dc4aSTimo Kreuzer
106*04e0dc4aSTimo Kreuzer return false;
107*04e0dc4aSTimo Kreuzer }
108*04e0dc4aSTimo Kreuzer
109*04e0dc4aSTimo Kreuzer
110*04e0dc4aSTimo Kreuzer
write_string_to_console(wchar_t const * const wide_string)111*04e0dc4aSTimo Kreuzer static void write_string_to_console(wchar_t const* const wide_string) throw()
112*04e0dc4aSTimo Kreuzer {
113*04e0dc4aSTimo Kreuzer HANDLE const handle = GetStdHandle(STD_ERROR_HANDLE);
114*04e0dc4aSTimo Kreuzer if (handle == nullptr || handle == INVALID_HANDLE_VALUE)
115*04e0dc4aSTimo Kreuzer {
116*04e0dc4aSTimo Kreuzer return;
117*04e0dc4aSTimo Kreuzer }
118*04e0dc4aSTimo Kreuzer
119*04e0dc4aSTimo Kreuzer // We convert the wide string to a narrow string by truncating each character.
120*04e0dc4aSTimo Kreuzer // Currently, the text for each runtime error consists only of ASCII, so this
121*04e0dc4aSTimo Kreuzer // is acceptable. If the error text is ever localized, this would need to
122*04e0dc4aSTimo Kreuzer // change.
123*04e0dc4aSTimo Kreuzer size_t const narrow_buffer_count = 500;
124*04e0dc4aSTimo Kreuzer char narrow_buffer[narrow_buffer_count];
125*04e0dc4aSTimo Kreuzer
126*04e0dc4aSTimo Kreuzer char* const narrow_first = narrow_buffer;
127*04e0dc4aSTimo Kreuzer char* const narrow_last = narrow_first + narrow_buffer_count;
128*04e0dc4aSTimo Kreuzer
129*04e0dc4aSTimo Kreuzer // Note that this loop copies the null terminator if the loop terminates
130*04e0dc4aSTimo Kreuzer // befoe running out of buffer space:
131*04e0dc4aSTimo Kreuzer char* narrow_it = narrow_first;
132*04e0dc4aSTimo Kreuzer wchar_t const* wide_it = wide_string;
133*04e0dc4aSTimo Kreuzer do
134*04e0dc4aSTimo Kreuzer {
135*04e0dc4aSTimo Kreuzer *narrow_it = static_cast<char>(*wide_it);
136*04e0dc4aSTimo Kreuzer }
137*04e0dc4aSTimo Kreuzer while (++narrow_it != narrow_last && *wide_it++ != '\0');
138*04e0dc4aSTimo Kreuzer
139*04e0dc4aSTimo Kreuzer // If we did run out of buffer space, this will null-terminate the text that
140*04e0dc4aSTimo Kreuzer // we were able to copy:
141*04e0dc4aSTimo Kreuzer *(narrow_last - 1) = '\0';
142*04e0dc4aSTimo Kreuzer
143*04e0dc4aSTimo Kreuzer DWORD const bytes_to_write = static_cast<DWORD>(narrow_it - narrow_first - 1); // Account for null terminator
144*04e0dc4aSTimo Kreuzer DWORD bytes_written = 0;
145*04e0dc4aSTimo Kreuzer WriteFile(handle, narrow_buffer, bytes_to_write, &bytes_written, nullptr);
146*04e0dc4aSTimo Kreuzer }
147*04e0dc4aSTimo Kreuzer
148*04e0dc4aSTimo Kreuzer
149*04e0dc4aSTimo Kreuzer
__acrt_report_runtime_error(wchar_t const * const message)150*04e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_report_runtime_error(wchar_t const* const message)
151*04e0dc4aSTimo Kreuzer {
152*04e0dc4aSTimo Kreuzer // Before we report the error via the normal path, report the error using
153*04e0dc4aSTimo Kreuzer // the debug
154*04e0dc4aSTimo Kreuzer if (issue_debug_notification(message))
155*04e0dc4aSTimo Kreuzer {
156*04e0dc4aSTimo Kreuzer return;
157*04e0dc4aSTimo Kreuzer }
158*04e0dc4aSTimo Kreuzer
159*04e0dc4aSTimo Kreuzer if (should_write_error_to_console())
160*04e0dc4aSTimo Kreuzer {
161*04e0dc4aSTimo Kreuzer write_string_to_console(message);
162*04e0dc4aSTimo Kreuzer }
163*04e0dc4aSTimo Kreuzer else
164*04e0dc4aSTimo Kreuzer {
165*04e0dc4aSTimo Kreuzer #define MSGTEXTPREFIX L"Runtime Error!\n\nProgram: "
166*04e0dc4aSTimo Kreuzer static wchar_t outmsg[sizeof(MSGTEXTPREFIX) / sizeof(wchar_t) + _MAX_PATH + 2 + 500];
167*04e0dc4aSTimo Kreuzer // runtime error msg + progname + 2 newline + runtime error text.
168*04e0dc4aSTimo Kreuzer wchar_t* progname = &outmsg[sizeof(MSGTEXTPREFIX) / sizeof(wchar_t) - 1];
169*04e0dc4aSTimo Kreuzer size_t progname_size = _countof(outmsg) - (progname - outmsg);
170*04e0dc4aSTimo Kreuzer wchar_t* pch = progname;
171*04e0dc4aSTimo Kreuzer
172*04e0dc4aSTimo Kreuzer _ERRCHECK(wcscpy_s(outmsg, _countof(outmsg), MSGTEXTPREFIX));
173*04e0dc4aSTimo Kreuzer
174*04e0dc4aSTimo Kreuzer progname[MAX_PATH] = L'\0';
175*04e0dc4aSTimo Kreuzer if (!GetModuleFileNameW(nullptr, progname, MAX_PATH))
176*04e0dc4aSTimo Kreuzer {
177*04e0dc4aSTimo Kreuzer _ERRCHECK(wcscpy_s(progname, progname_size, L"<program name unknown>"));
178*04e0dc4aSTimo Kreuzer }
179*04e0dc4aSTimo Kreuzer
180*04e0dc4aSTimo Kreuzer #define MAXLINELEN 60
181*04e0dc4aSTimo Kreuzer if (wcslen(pch) + 1 > MAXLINELEN)
182*04e0dc4aSTimo Kreuzer {
183*04e0dc4aSTimo Kreuzer pch += wcslen(progname) + 1 - MAXLINELEN;
184*04e0dc4aSTimo Kreuzer _ERRCHECK(wcsncpy_s(pch, progname_size - (pch - progname), L"...", 3));
185*04e0dc4aSTimo Kreuzer }
186*04e0dc4aSTimo Kreuzer
187*04e0dc4aSTimo Kreuzer _ERRCHECK(wcscat_s(outmsg, _countof(outmsg), L"\n\n"));
188*04e0dc4aSTimo Kreuzer _ERRCHECK(wcscat_s(outmsg, _countof(outmsg), message));
189*04e0dc4aSTimo Kreuzer
190*04e0dc4aSTimo Kreuzer // Okay to ignore return value here, this is just to display the message box.
191*04e0dc4aSTimo Kreuzer // Only caller is abort() (so we shouldn't/can't handle IDABORT), so the process
192*04e0dc4aSTimo Kreuzer // will end shortly.
193*04e0dc4aSTimo Kreuzer __acrt_show_wide_message_box(
194*04e0dc4aSTimo Kreuzer outmsg,
195*04e0dc4aSTimo Kreuzer L"Microsoft Visual C++ Runtime Library",
196*04e0dc4aSTimo Kreuzer MB_OK | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL);
197*04e0dc4aSTimo Kreuzer }
198*04e0dc4aSTimo Kreuzer }
199*04e0dc4aSTimo Kreuzer
200*04e0dc4aSTimo Kreuzer #endif /* _UCRT_ENCLAVE_BUILD */
201