mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:22:45 +00:00 
			
		
		
		
	AK: Always use our assertion failure method, and add backtrace to it
On platforms that support it, enable using ``<execinfo.h>`` to get backtrace(3) to dump a backtrace on assertion failure. This should make debugging things like WebContent crashes in Lagom much easier.
This commit is contained in:
		
							parent
							
								
									3056ff6b11
								
							
						
					
					
						commit
						4641af7873
					
				
					 3 changed files with 65 additions and 10 deletions
				
			
		|  | @ -6,13 +6,68 @@ | |||
| 
 | ||||
| #include <AK/Assertions.h> | ||||
| #include <AK/Format.h> | ||||
| #include <AK/Platform.h> | ||||
| #include <AK/StringView.h> | ||||
| 
 | ||||
| #if defined(AK_OS_LINUX) || defined(AK_OS_BSD_GENERIC) || defined(AK_OS_SOLARIS) | ||||
| #    define EXECINFO_BACKTRACE | ||||
| #endif | ||||
| 
 | ||||
| #if defined(EXECINFO_BACKTRACE) | ||||
| #    include <cxxabi.h> | ||||
| #    include <execinfo.h> | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(KERNEL) | ||||
| 
 | ||||
| #    if defined(EXECINFO_BACKTRACE) | ||||
| namespace { | ||||
| ALWAYS_INLINE void dump_backtrace() | ||||
| { | ||||
|     // Grab symbols and dso name for up to 256 frames
 | ||||
|     void* trace[256] = {}; | ||||
|     int const num_frames = backtrace(trace, sizeof(trace)); | ||||
|     char** syms = backtrace_symbols(trace, num_frames); | ||||
| 
 | ||||
|     for (auto i = 0; i < num_frames; ++i) { | ||||
|         // If there is a C++ symbol name in the line of the backtrace, demangle it
 | ||||
|         StringView sym(syms[i], strlen(syms[i])); | ||||
|         if (auto idx = sym.find("_Z"sv); idx.has_value()) { | ||||
|             // Play C games with the original string so we can print before and after the mangled symbol with a C API
 | ||||
|             // We don't want to call dbgln() here on substring StringView because we might VERIFY() within AK::Format
 | ||||
|             syms[i][idx.value() - 1] = '\0'; | ||||
|             (void)fprintf(stderr, "%s ", syms[i]); | ||||
| 
 | ||||
|             auto end_of_sym = sym.find(' ', idx.value()).value_or(sym.length() - 1); | ||||
|             syms[i][end_of_sym] = '\0'; | ||||
| 
 | ||||
|             size_t buf_size = 128u; | ||||
|             char* buf = static_cast<char*>(malloc(buf_size)); | ||||
|             auto* raw_str = &syms[i][idx.value()]; | ||||
|             buf = abi::__cxa_demangle(raw_str, buf, &buf_size, nullptr); | ||||
| 
 | ||||
|             (void)fputs(buf ? buf : raw_str, stderr); | ||||
|             free(buf); | ||||
| 
 | ||||
|             (void)fprintf(stderr, " %s", &syms[i][end_of_sym + 1]); | ||||
|         } else { | ||||
|             (void)fputs(sym.characters_without_null_termination(), stderr); | ||||
|         } | ||||
|         (void)fputs("\n", stderr); | ||||
|     } | ||||
|     free(syms); | ||||
| } | ||||
| } | ||||
| #    endif | ||||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
| void ak_verification_failed(char const* message) | ||||
| { | ||||
|     dbgln("VERIFICATION FAILED: {}", message); | ||||
| #    if defined(EXECINFO_BACKTRACE) | ||||
|     dump_backtrace(); | ||||
| #    endif | ||||
|     __builtin_trap(); | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -11,16 +11,12 @@ | |||
| #else | ||||
| #    include <assert.h> | ||||
| extern "C" __attribute__((noreturn)) void ak_verification_failed(char const*); | ||||
| #    if !defined(NDEBUG) && !defined(WIN32) | ||||
| #        define VERIFY assert | ||||
| #    else | ||||
| #        define __stringify_helper(x) #x | ||||
| #        define __stringify(x) __stringify_helper(x) | ||||
| #        define VERIFY(expr)                                                                \ | ||||
|             (__builtin_expect(!(expr), 0)                                                   \ | ||||
|                     ? ak_verification_failed(#expr "\n" __FILE__ ":" __stringify(__LINE__)) \ | ||||
|                     : (void)0) | ||||
| #    endif | ||||
| #    define __stringify_helper(x) #x | ||||
| #    define __stringify(x) __stringify_helper(x) | ||||
| #    define VERIFY(expr)                                                                  \ | ||||
|         (__builtin_expect(!(expr), 0)                                                     \ | ||||
|                 ? ak_verification_failed(#expr " at " __FILE__ ":" __stringify(__LINE__)) \ | ||||
|                 : (void)0) | ||||
| #    define VERIFY_NOT_REACHED() VERIFY(false) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */ | ||||
| static constexpr bool TODO = false; | ||||
| #    define TODO() VERIFY(TODO)                /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */ | ||||
|  |  | |||
|  | @ -331,6 +331,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") | |||
|     # Solaris has socket and networking related functions in two extra libraries | ||||
|     target_link_libraries(LibCore PRIVATE nsl socket) | ||||
| endif() | ||||
| if (${CMAKE_SYSTEM_NAME} MATCHES "BSD$") | ||||
|     # BSD Platforms have backtrace(3) in a separate library | ||||
|     target_link_libraries(LibCore PRIVATE execinfo) | ||||
| endif() | ||||
| target_sources(LibCore PRIVATE ${AK_SOURCES}) | ||||
| 
 | ||||
| # LibMain | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andrew Kaster
						Andrew Kaster