Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445/****assert.c - Display a message and abort** Copyright (c) Microsoft Corporation. All rights reserved.**Purpose:********************************************************************************/
#include <corecrt_internal.h>#include <corecrt_internal_stdio.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <string.h>
#undef NDEBUG#define _ASSERT_OK#include <assert.h>
// Assertion string components:#define MAXLINELEN 64 /* max length for line in message box */#define ASSERTBUFSZ (MAXLINELEN * 9) /* 9 lines in message box */
// Format of stderr for assertions://// Assertion failed: <expression>, file c:\test\mytest\bar.c, line 69//
_GENERATE_TCHAR_STRING_FUNCTIONS(assert_format, "Assertion failed: %Ts, file %Ts, line %d\n")
// Enclaves only support assertions sent to the debugger.// This mode could also be enabled for normal apps as well.
#ifdef _UCRT_ENCLAVE_BUILD
template <typename Character>__declspec(noreturn) static void __cdecl common_assert_to_debug( Character const* const expression, Character const* const file_name, unsigned const line_number ) throw(){ using traits = __crt_char_traits<Character>;
Character assert_buffer[ASSERTBUFSZ]; if (traits::sntprintf_s(assert_buffer, _countof(assert_buffer), _countof(assert_buffer), get_assert_format(Character()), expression, file_name, line_number) < 0) { abort(); } traits::output_debug_string(assert_buffer); abort();}
template <typename Character>static void __cdecl common_assert( Character const* const expression, Character const* const file_name, unsigned const line_number, void* const ) throw(){ common_assert_to_debug(expression, file_name, line_number);}
#else /* ^^^ _UCRT_ENCLAVE_BUILD ^^^ // vvv !_UCRT_ENCLAVE_BUILD vvv */
// Format of MessageBox for assertions://// ================= Microsft Visual C++ Debug Library ================//// Assertion Failed!//// Program: c:\test\mytest\foo.exe// File: c:\test\mytest\bar.c// Line: 69//// Expression: <expression>//// For information on how your program can cause an assertion// failure, see the Visual C++ documentation on asserts//// (Press Retry to debug the application - JIT must be enabled)//// ===================================================================
_GENERATE_TCHAR_STRING_FUNCTIONS(banner_text, "Microsoft Visual C++ Runtime Library")
_GENERATE_TCHAR_STRING_FUNCTIONS(box_intro, "Assertion failed!")_GENERATE_TCHAR_STRING_FUNCTIONS(program_intro, "Program: ")_GENERATE_TCHAR_STRING_FUNCTIONS(file_intro, "File: ")_GENERATE_TCHAR_STRING_FUNCTIONS(line_intro, "Line: ")_GENERATE_TCHAR_STRING_FUNCTIONS(expression_intro, "Expression: ")_GENERATE_TCHAR_STRING_FUNCTIONS(info_intro, "For information on how your program can cause an assertion\nfailure, see the Visual C++ documentation on asserts")_GENERATE_TCHAR_STRING_FUNCTIONS(help_intro, "(Press Retry to debug the application - JIT must be enabled)")
_GENERATE_TCHAR_STRING_FUNCTIONS(dot_dot_dot, "...")_GENERATE_TCHAR_STRING_FUNCTIONS(newline, "\n")_GENERATE_TCHAR_STRING_FUNCTIONS(double_newline, "\n\n")
_GENERATE_TCHAR_STRING_FUNCTIONS(program_name_unknown_text, "<program name unknown>")
/****_assert() - Display a message and abort**Purpose:* The assert macro calls this routine if the assert expression is* true. By placing the assert code in a subroutine instead of within* the body of the macro, programs that call assert multiple times will* save space.**Entry:**Exit:**Exceptions:********************************************************************************/static void __cdecl common_assert_to_stderr_direct(char const*, char const*, unsigned) throw(){ // No action for narrow strings}
static void __cdecl common_assert_to_stderr_direct( wchar_t const* const expression, wchar_t const* const file_name, unsigned const line_number ) throw(){ HANDLE const stderr_handle = GetStdHandle(STD_ERROR_HANDLE);#pragma warning(suppress:__WARNING_REDUNDANT_POINTER_TEST) // 28922 if (stderr_handle == INVALID_HANDLE_VALUE || stderr_handle == nullptr) { return; }
if (GetFileType(stderr_handle) != FILE_TYPE_CHAR) { return; }
wchar_t assert_buffer[ASSERTBUFSZ];#pragma warning(suppress:__WARNING_BANNED_API_USAGE) // 28719 if (swprintf(assert_buffer, _countof(assert_buffer), get_assert_format(wchar_t()), expression, file_name, line_number) < 0) { return; }
DWORD const assert_buffer_length = static_cast<DWORD>(wcslen(assert_buffer)); DWORD characters_written = 0; if (WriteConsoleW(stderr_handle, assert_buffer, assert_buffer_length, &characters_written, nullptr) == 0) { return; }
abort();}
template <typename Character>__declspec(noreturn) static void __cdecl common_assert_to_stderr( Character const* const expression, Character const* const file_name, unsigned const line_number ) throw(){ using traits = __crt_char_traits<Character>;
// Try to write directly to the console. This is only supported for wide // character strings. If we have a narrow character string or the write // fails, we fall back to call through stdio. common_assert_to_stderr_direct(expression, file_name, line_number);
// If stderr does not yet have a buffer, set it to use single character // buffering to avoid dynamic allocation of a stream buffer: if (!__crt_stdio_stream(stderr).has_any_buffer()) { setvbuf(stderr, nullptr, _IONBF, 0); }
traits::ftprintf(stderr, get_assert_format(Character()), expression, file_name, line_number); fflush(stderr); abort();}
template <typename Character>static void __cdecl common_assert_to_message_box_build_string( Character* const assert_buffer, size_t const assert_buffer_count, Character const* const expression, Character const* const file_name, unsigned const line_number, void* const return_address ) throw(){ using traits = __crt_char_traits<Character>;
// Line 1: Box introduction line: _ERRCHECK(traits::tcscpy_s(assert_buffer, assert_buffer_count, get_box_intro(Character()))); _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_double_newline(Character())));
// Line 2: Program line: _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_program_intro(Character())));
Character program_name[_MAX_PATH + 1]{};
HMODULE asserting_module = nullptr; if (!GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<wchar_t const*>(return_address), &asserting_module)) { asserting_module = nullptr; }
#ifdef CRTDLL // If the assert came from within the CRT DLL, report it as having come // from the EXE instead: if (asserting_module == reinterpret_cast<HMODULE>(&__ImageBase)) { asserting_module = nullptr; } #endif
if (!traits::get_module_file_name(asserting_module, program_name, static_cast<DWORD>(_countof(program_name)))) { _ERRCHECK(traits::tcscpy_s(program_name, _countof(program_name), get_program_name_unknown_text(Character()))); }
Character* pchProg = program_name; if (program_intro_count + traits::tcslen(program_name) + newline_length > MAXLINELEN) { pchProg += (program_intro_count + traits::tcslen(program_name) + newline_length) - MAXLINELEN; // Only replace first (sizeof(Character) * dot_dot_dot_length) bytes to ellipsis: _ERRCHECK(memcpy_s( pchProg, sizeof(Character) * ((MAX_PATH + 1) - (pchProg - program_name)), get_dot_dot_dot(Character()), sizeof(Character) * dot_dot_dot_length )); }
_ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, pchProg)); _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_newline(Character())));
// Line 3: File line _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_file_intro(Character())));
if (file_intro_count + traits::tcslen(file_name) + newline_length > MAXLINELEN) { size_t const ffn = MAXLINELEN - file_intro_count - newline_length;
size_t p = 0; size_t len = 0; Character const* pch = file_name; for (len = traits::tcslen(file_name), p = 1; pch[len - p] != '\\' && pch[len - p] != '/' && p < len; p++) { }
// Trim the path and file name so that they fit, using up to 2/3 of // the maximum number of characters for the path and the remaining // 1/3 for the file name: if ((ffn - ffn / 3) < (len - p) && ffn / 3 > p) { // The path is too long. Use the first part of the path and the // full file name: _ERRCHECK(traits::tcsncat_s(assert_buffer, assert_buffer_count, pch, ffn - dot_dot_dot_length - p)); _ERRCHECK(traits::tcscat_s (assert_buffer, assert_buffer_count, get_dot_dot_dot(Character()))); _ERRCHECK(traits::tcscat_s (assert_buffer, assert_buffer_count, pch + len - p)); } else if (ffn - ffn / 3 > len - p) { // The file name is too long. Use the full path and the first // and last part of the file name, with a ... in between: p = p / 2; _ERRCHECK(traits::tcsncat_s(assert_buffer, assert_buffer_count, pch, ffn - dot_dot_dot_length - p)); _ERRCHECK(traits::tcscat_s (assert_buffer, assert_buffer_count, get_dot_dot_dot(Character()))); _ERRCHECK(traits::tcscat_s (assert_buffer, assert_buffer_count, pch + len - p)); } else { // Both are too long. Use the first part of the path and the // first and last part of the file name, with ...s in between: _ERRCHECK(traits::tcsncat_s(assert_buffer, assert_buffer_count, pch, ffn - ffn / 3 - dot_dot_dot_length)); _ERRCHECK(traits::tcscat_s (assert_buffer, assert_buffer_count, get_dot_dot_dot(Character()))); _ERRCHECK(traits::tcsncat_s(assert_buffer, assert_buffer_count, pch + len - p, ffn / 6 - 1)); _ERRCHECK(traits::tcscat_s (assert_buffer, assert_buffer_count, get_dot_dot_dot(Character()))); _ERRCHECK(traits::tcscat_s (assert_buffer, assert_buffer_count, pch + len - (ffn / 3 - ffn / 6 - 2))); } } else { // Plenty of room on the line; just append the full path and file name: _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, file_name)); }
_ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_newline(Character())));
// Line 4: Line Number line: _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_line_intro(Character()))); _ERRCHECK(traits::itot_s( line_number, assert_buffer + traits::tcslen(assert_buffer), assert_buffer_count - traits::tcslen(assert_buffer), 10)); _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_double_newline(Character())));
// Line 5: Message line: _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_expression_intro(Character())));
size_t const characters_used = traits::tcslen(assert_buffer) + 2 * double_newline_length + info_intro_length + help_intro_count;
if (characters_used + traits::tcslen(expression) > assert_buffer_count) { size_t const characters_to_write = assert_buffer_count - (characters_used + dot_dot_dot_length); _ERRCHECK(traits::tcsncat_s( assert_buffer, assert_buffer_count, expression, characters_to_write)); _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_dot_dot_dot(Character()))); } else { _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, expression)); }
_ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_double_newline(Character())));
// Info line: _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_info_intro(Character()))); _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_double_newline(Character())));
// Help line: _ERRCHECK(traits::tcscat_s(assert_buffer, assert_buffer_count, get_help_intro(Character())));}
template <typename Character>static void __cdecl common_assert_to_message_box( Character const* const expression, Character const* const file_name, unsigned const line_number, void* const return_address ) throw(){ using traits = __crt_char_traits<Character>;
Character assert_buffer[ASSERTBUFSZ]{}; common_assert_to_message_box_build_string( assert_buffer, _countof(assert_buffer), expression, file_name, line_number, return_address);
int const action = traits::show_message_box( assert_buffer, get_banner_text(Character()), MB_TASKMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE | MB_SETFOREGROUND);
switch (action) { case IDABORT: // Abort the program: { raise(SIGABRT);
// We won't usually get here, but it's possible that a user-registered // abort handler returns, so exit the program immediately. Note that // even though we are "aborting," we do not call abort() because we do // not want to invoke Watson (the user has already had an opportunity // to debug the error and chose not to). _exit(3); } case IDRETRY: // Break into the debugger then return control to caller { __debugbreak(); return; } case IDIGNORE: // Return control to caller { return; } default: // This should not happen; treat as fatal error: { abort(); } }}
template <typename Character>static void __cdecl common_assert( Character const* const expression, Character const* const file_name, unsigned const line_number, void* const return_address ) throw(){ using traits = __crt_char_traits<Character>;
int const current_error_mode = _set_error_mode(_REPORT_ERRMODE); if (current_error_mode == _OUT_TO_STDERR) { return common_assert_to_stderr(expression, file_name, line_number); }
if (current_error_mode == _OUT_TO_DEFAULT && _query_app_type() == _crt_console_app) { return common_assert_to_stderr(expression, file_name, line_number); }
return common_assert_to_message_box(expression, file_name, line_number, return_address);}
#endif /* _UCRT_ENCLAVE_BUILD */
extern "C" void __cdecl _assert( char const* const expression, char const* const file_name, unsigned const line_number ) throw(){ return common_assert(expression, file_name, line_number, _ReturnAddress());}
extern "C" void __cdecl _wassert( wchar_t const* const expression, wchar_t const* const file_name, unsigned const line_number ) { return common_assert(expression, file_name, line_number, _ReturnAddress());}