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