diff --git a/category/core/CMakeLists.txt b/category/core/CMakeLists.txt index f908fa81c..64fa09193 100644 --- a/category/core/CMakeLists.txt +++ b/category/core/CMakeLists.txt @@ -74,6 +74,8 @@ add_library( "assert.h" "backtrace.cpp" "backtrace.hpp" + "terminate_handler.cpp" + "terminate_handler.h" "basic_formatter.hpp" "blake3.hpp" "byte_string.hpp" diff --git a/category/core/config.hpp b/category/core/config.hpp index 888aed5c8..8fed91dd8 100644 --- a/category/core/config.hpp +++ b/category/core/config.hpp @@ -35,6 +35,14 @@ } \ MONAD_NAMESPACE_END +// Macro for marking C++ functions as noexcept in C++ mode, empty in C mode +// This is primarily used for extern "C" functions that should not throw +#ifdef __cplusplus + #define MONAD_NOEXCEPT noexcept +#else + #define MONAD_NOEXCEPT +#endif + static_assert(CHAR_BIT == 8); static_assert( diff --git a/category/core/terminate_handler.cpp b/category/core/terminate_handler.cpp new file mode 100644 index 000000000..1334d5ef5 --- /dev/null +++ b/category/core/terminate_handler.cpp @@ -0,0 +1,148 @@ +// Copyright (C) 2025 Category Labs, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +#include +#include +#include +#include +#include +#include +#include + +extern char const *__progname; // NOLINT(bugprone-reserved-identifier) + +extern "C" void monad_stack_backtrace_capture_and_print( + char *buffer, size_t size, int fd, unsigned indent, + bool print_async_unsafe_info); + +namespace +{ + void monad_terminate_handler_impl() noexcept + { + char buffer[16384]; + ssize_t written = 0; + + // Print header + written = snprintf( + buffer, + sizeof(buffer), + "\n" + "==================================================================" + "==============\n" + "%s: std::terminate() called\n" + "==================================================================" + "==============\n", + __progname); + + if (written > 0 && (size_t)written < sizeof(buffer)) { + if (write(STDERR_FILENO, buffer, (size_t)written) == -1) { + // Suppress warning + } + } + + // Try to get exception information + std::type_info *exception_type = abi::__cxa_current_exception_type(); + if (exception_type != nullptr) { + char const *exception_name = exception_type->name(); + + // Try to demangle the name + int status = 0; + char *demangled = + abi::__cxa_demangle(exception_name, nullptr, nullptr, &status); + char const *display_name = (status == 0 && demangled != nullptr) + ? demangled + : exception_name; + + written = snprintf( + buffer, + sizeof(buffer), + "Reason: Uncaught exception\n" + "Exception type: %s\n", + display_name); + + if (written > 0 && (size_t)written < sizeof(buffer)) { + if (write(STDERR_FILENO, buffer, (size_t)written) == -1) { + // Suppress warning + } + } + + // Try to get exception message if it's a std::exception + try { + std::rethrow_exception(std::current_exception()); + } + catch (std::exception const &e) { + written = snprintf( + buffer, + sizeof(buffer), + "Exception message: %s\n", + e.what()); + + if (written > 0 && (size_t)written < sizeof(buffer)) { + if (write(STDERR_FILENO, buffer, (size_t)written) == -1) { + // Suppress warning + } + } + } + catch (...) { + // Not a std::exception, no message available + char const *msg = "Exception message: \n"; + if (write(STDERR_FILENO, msg, strlen(msg)) == -1) { + // Suppress warning + } + } + + if (demangled != nullptr) { + free(demangled); + } + } + else { + // No active exception - std::terminate() was called for another + // reason. + char const *msg = "No active exception detected\n"; + if (write(STDERR_FILENO, msg, strlen(msg)) == -1) { + // Suppress warning + } + } + + char const *separator = "----------------------------------------------" + "----------------------------------\n" + "Stack trace:\n" + "----------------------------------------------" + "----------------------------------\n"; + if (write(STDERR_FILENO, separator, strlen(separator)) == -1) { + // Suppress warning + } + + monad_stack_backtrace_capture_and_print( + buffer, sizeof(buffer), STDERR_FILENO, 3, true); + + char const *footer = "=================================================" + "===============================\n" + "Aborting process...\n" + "=================================================" + "===============================\n"; + if (write(STDERR_FILENO, footer, strlen(footer)) == -1) { + // Suppress warning + } + abort(); + } +} + +extern "C" void monad_set_terminate_handler() +{ + std::set_terminate(monad_terminate_handler_impl); +} diff --git a/category/core/terminate_handler.h b/category/core/terminate_handler.h new file mode 100644 index 000000000..8757ec6f2 --- /dev/null +++ b/category/core/terminate_handler.h @@ -0,0 +1,30 @@ +// Copyright (C) 2025 Category Labs, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +/// Install custom terminate handler that prints exception info and backtrace +/// before aborting. This should be called early in main() to catch exceptions +/// that escape noexcept functions (e.g., FFI boundaries). +void monad_set_terminate_handler(); + +#ifdef __cplusplus +} +#endif diff --git a/category/core/test/CMakeLists.txt b/category/core/test/CMakeLists.txt index 645ede98d..8d9770608 100644 --- a/category/core/test/CMakeLists.txt +++ b/category/core/test/CMakeLists.txt @@ -36,3 +36,4 @@ monad_add_test(monad_exception_test "monad_exception.cpp") monad_add_test(path_util_test "path_util.cpp") monad_add_test(priority_pool_test "priority_pool_test.cpp") set_tests_properties(priority_pool_test PROPERTIES RUN_SERIAL TRUE) +monad_add_test(terminate_handler_test "terminate_handler_test.cpp") diff --git a/category/core/test/terminate_handler_test.cpp b/category/core/test/terminate_handler_test.cpp new file mode 100644 index 000000000..585974a5a --- /dev/null +++ b/category/core/test/terminate_handler_test.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2025 Category Labs, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +#include + +#include +#include + +namespace +{ + + void throwing_function() + { + throw std::runtime_error("Test exception from throwing_function"); + } + + // NOLINTNEXTLINE(bugprone-exception-escape) + void noexcept_function() noexcept + { + // This will call std::terminate because we're throwing from noexcept + throwing_function(); + } + +} // namespace + +// Death tests must be named with DeathTest suffix for proper test ordering +TEST(TerminateHandlerDeathTest, ExceptionEscapingNoexcept) +{ + // Install the custom terminate handler + monad_set_terminate_handler(); + + // Verify that calling noexcept_function causes termination + // and that the output contains expected exception information + EXPECT_DEATH( + { noexcept_function(); }, + // Regex pattern matching expected output: + // - Should contain "std::terminate" or "terminate()" + // - Should contain the exception type "runtime_error" + // - Should contain the exception message + // - Should contain "Stack trace" + "std::terminate.*" + ".*runtime_error.*" + ".*Test exception from throwing_function.*" + ".*Stack trace.*"); +} + +TEST(TerminateHandlerDeathTest, DirectTerminateCall) +{ + // Install the custom terminate handler + monad_set_terminate_handler(); + + // Verify that directly calling std::terminate works + EXPECT_DEATH( + { std::terminate(); }, + // Should indicate no active exception + "std::terminate.*" + ".*No active exception detected.*" + ".*Stack trace.*"); +} + +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wexceptions" +#else + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wterminate" +#endif + +// Helper function for testing different exception type +// NOLINTNEXTLINE(bugprone-exception-escape) +[[noreturn]] void throw_logic_error_noexcept() noexcept +{ + throw std::logic_error("Logic error test"); +} + +#ifdef __clang__ + #pragma clang diagnostic pop +#else + #pragma GCC diagnostic pop +#endif + +TEST(TerminateHandlerDeathTest, ExceptionTypeInOutput) +{ + // Install the custom terminate handler + monad_set_terminate_handler(); + + // Test with a different exception type + EXPECT_DEATH( + { throw_logic_error_noexcept(); }, + "std::terminate.*" + ".*logic_error.*" + ".*Logic error test.*"); +} diff --git a/category/rpc/eth_call.cpp b/category/rpc/eth_call.cpp index 913581b6f..4344a0145 100644 --- a/category/rpc/eth_call.cpp +++ b/category/rpc/eth_call.cpp @@ -248,14 +248,14 @@ namespace monad quill::Logger *tracer = nullptr; } -monad_state_override *monad_state_override_create() +monad_state_override *monad_state_override_create() noexcept { monad_state_override *const m = new monad_state_override(); return m; } -void monad_state_override_destroy(monad_state_override *const m) +void monad_state_override_destroy(monad_state_override *const m) noexcept { MONAD_ASSERT(m); delete m; @@ -263,7 +263,7 @@ void monad_state_override_destroy(monad_state_override *const m) void add_override_address( monad_state_override *const m, uint8_t const *const addr, - size_t const addr_len) + size_t const addr_len) noexcept { MONAD_ASSERT(m); @@ -278,7 +278,7 @@ void add_override_address( void set_override_balance( monad_state_override *const m, uint8_t const *const addr, size_t const addr_len, uint8_t const *const balance, - size_t const balance_len) + size_t const balance_len) noexcept { MONAD_ASSERT(m); @@ -294,7 +294,7 @@ void set_override_balance( void set_override_nonce( monad_state_override *const m, uint8_t const *const addr, - size_t const addr_len, uint64_t const nonce) + size_t const addr_len, uint64_t const nonce) noexcept { MONAD_ASSERT(m); @@ -308,7 +308,8 @@ void set_override_nonce( void set_override_code( monad_state_override *const m, uint8_t const *const addr, - size_t const addr_len, uint8_t const *const code, size_t const code_len) + size_t const addr_len, uint8_t const *const code, + size_t const code_len) noexcept { MONAD_ASSERT(m); @@ -325,7 +326,7 @@ void set_override_code( void set_override_state_diff( monad_state_override *const m, uint8_t const *const addr, size_t const addr_len, uint8_t const *const key, size_t const key_len, - uint8_t const *const value, size_t const value_len) + uint8_t const *const value, size_t const value_len) noexcept { MONAD_ASSERT(m); @@ -349,7 +350,7 @@ void set_override_state_diff( void set_override_state( monad_state_override *const m, uint8_t const *const addr, size_t const addr_len, uint8_t const *const key, size_t const key_len, - uint8_t const *const value, size_t const value_len) + uint8_t const *const value, size_t const value_len) noexcept { MONAD_ASSERT(m); @@ -370,7 +371,7 @@ void set_override_state( state_object.emplace(k, std::move(v)); } -void monad_eth_call_result_release(monad_eth_call_result *const result) +void monad_eth_call_result_release(monad_eth_call_result *const result) noexcept { MONAD_ASSERT(result); if (result->output_data) { @@ -887,7 +888,7 @@ struct monad_eth_call_executor monad_eth_call_executor *monad_eth_call_executor_create( monad_eth_call_pool_config const low_pool_conf, monad_eth_call_pool_config const high_pool_conf, - uint64_t const node_lru_max_mem, char const *const dbpath) + uint64_t const node_lru_max_mem, char const *const dbpath) noexcept { MONAD_ASSERT(dbpath); std::string const triedb_path{dbpath}; @@ -898,7 +899,7 @@ monad_eth_call_executor *monad_eth_call_executor_create( return e; } -void monad_eth_call_executor_destroy(monad_eth_call_executor *const e) +void monad_eth_call_executor_destroy(monad_eth_call_executor *const e) noexcept { MONAD_ASSERT(e); @@ -915,7 +916,7 @@ void monad_eth_call_executor_submit( monad_state_override const *const overrides, void (*complete)(monad_eth_call_result *result, void *user), void *const user, monad_tracer_config const tracer_config, - bool const gas_specified) + bool const gas_specified) noexcept { MONAD_ASSERT(executor); @@ -961,7 +962,7 @@ void monad_eth_call_executor_submit( } struct monad_eth_call_executor_state -monad_eth_call_executor_get_state(monad_eth_call_executor *const e) +monad_eth_call_executor_get_state(monad_eth_call_executor *const e) noexcept { MONAD_ASSERT(e); return monad_eth_call_executor_state{ diff --git a/category/rpc/eth_call.h b/category/rpc/eth_call.h index 3a597c605..97aa1b2c4 100644 --- a/category/rpc/eth_call.h +++ b/category/rpc/eth_call.h @@ -15,6 +15,7 @@ #pragma once +#include #include #include @@ -31,34 +32,35 @@ static uint64_t const MONAD_ETH_CALL_LOW_GAS_LIMIT = 400'000; struct monad_state_override; struct monad_eth_call_executor; -struct monad_state_override *monad_state_override_create(); +struct monad_state_override *monad_state_override_create() MONAD_NOEXCEPT; -void monad_state_override_destroy(struct monad_state_override *); +void monad_state_override_destroy(struct monad_state_override *) MONAD_NOEXCEPT; void add_override_address( - struct monad_state_override *, uint8_t const *addr, size_t addr_len); + struct monad_state_override *, uint8_t const *addr, + size_t addr_len) MONAD_NOEXCEPT; void set_override_balance( struct monad_state_override *, uint8_t const *addr, size_t addr_len, - uint8_t const *balance, size_t balance_len); + uint8_t const *balance, size_t balance_len) MONAD_NOEXCEPT; void set_override_nonce( struct monad_state_override *, uint8_t const *addr, size_t addr_len, - uint64_t nonce); + uint64_t nonce) MONAD_NOEXCEPT; void set_override_code( struct monad_state_override *, uint8_t const *addr, size_t addr_len, - uint8_t const *code, size_t code_len); + uint8_t const *code, size_t code_len) MONAD_NOEXCEPT; void set_override_state_diff( struct monad_state_override *, uint8_t const *addr, size_t addr_len, uint8_t const *key, size_t key_len, uint8_t const *value, - size_t valuen_len); + size_t valuen_len) MONAD_NOEXCEPT; void set_override_state( struct monad_state_override *, uint8_t const *addr, size_t addr_len, uint8_t const *key, size_t key_len, uint8_t const *value, - size_t valuen_len); + size_t valuen_len) MONAD_NOEXCEPT; typedef struct monad_eth_call_result { @@ -76,7 +78,7 @@ typedef struct monad_eth_call_result size_t encoded_trace_len; } monad_eth_call_result; -void monad_eth_call_result_release(monad_eth_call_result *); +void monad_eth_call_result_release(monad_eth_call_result *) MONAD_NOEXCEPT; struct monad_eth_call_pool_config { @@ -121,9 +123,10 @@ struct monad_eth_call_executor_state struct monad_eth_call_executor *monad_eth_call_executor_create( struct monad_eth_call_pool_config low_pool_conf, struct monad_eth_call_pool_config high_pool_conf, uint64_t node_lru_max_mem, - char const *dbpath); + char const *dbpath) MONAD_NOEXCEPT; -void monad_eth_call_executor_destroy(struct monad_eth_call_executor *); +void monad_eth_call_executor_destroy(struct monad_eth_call_executor *) + MONAD_NOEXCEPT; void monad_eth_call_executor_submit( struct monad_eth_call_executor *, enum monad_chain_config, @@ -132,10 +135,10 @@ void monad_eth_call_executor_submit( uint64_t block_number, uint8_t const *rlp_block_id, size_t rlp_block_id_len, struct monad_state_override const *, void (*complete)(monad_eth_call_result *, void *user), void *user, - enum monad_tracer_config, bool gas_specified); + enum monad_tracer_config, bool gas_specified) MONAD_NOEXCEPT; -struct monad_eth_call_executor_state -monad_eth_call_executor_get_state(struct monad_eth_call_executor *); +struct monad_eth_call_executor_state monad_eth_call_executor_get_state( + struct monad_eth_call_executor *) MONAD_NOEXCEPT; #ifdef __cplusplus } diff --git a/category/statesync/statesync_client.cpp b/category/statesync/statesync_client.cpp index df3788072..507786a85 100644 --- a/category/statesync/statesync_client.cpp +++ b/category/statesync/statesync_client.cpp @@ -40,7 +40,7 @@ monad_statesync_client_context *monad_statesync_client_context_create( char const *const *const dbname_paths, size_t const len, unsigned const sq_thread_cpu, monad_statesync_client *sync, void (*statesync_send_request)( - monad_statesync_client *, monad_sync_request)) + monad_statesync_client *, monad_sync_request)) noexcept { std::vector const paths{ dbname_paths, dbname_paths + len}; @@ -54,18 +54,18 @@ monad_statesync_client_context *monad_statesync_client_context_create( statesync_send_request}; } -uint8_t monad_statesync_client_prefix_bytes() +uint8_t monad_statesync_client_prefix_bytes() noexcept { return 1; } -size_t monad_statesync_client_prefixes() +size_t monad_statesync_client_prefixes() noexcept { return 1 << (8 * monad_statesync_client_prefix_bytes()); } bool monad_statesync_client_has_reached_target( - monad_statesync_client_context const *const ctx) + monad_statesync_client_context const *const ctx) noexcept { if (ctx->tgrt.number == INVALID_BLOCK_NUM) { return false; @@ -82,7 +82,7 @@ bool monad_statesync_client_has_reached_target( void monad_statesync_client_handle_new_peer( monad_statesync_client_context *const ctx, uint64_t const prefix, - uint32_t const version) + uint32_t const version) noexcept { MONAD_ASSERT(monad_statesync_client_compatible(version)); auto &ptr = ctx->protocol.at(prefix); @@ -99,7 +99,7 @@ void monad_statesync_client_handle_new_peer( void monad_statesync_client_handle_target( monad_statesync_client_context *const ctx, unsigned char const *const data, - uint64_t const size) + uint64_t const size) noexcept { MONAD_ASSERT(std::ranges::all_of( ctx->protocol, [](auto const &ptr) { return ptr != nullptr; })) @@ -131,13 +131,14 @@ void monad_statesync_client_handle_target( bool monad_statesync_client_handle_upsert( monad_statesync_client_context *const ctx, uint64_t const prefix, monad_sync_type const type, unsigned char const *const val, - uint64_t const size) + uint64_t const size) noexcept { return ctx->protocol.at(prefix)->handle_upsert(ctx, type, val, size); } void monad_statesync_client_handle_done( - monad_statesync_client_context *const ctx, monad_sync_done const msg) + monad_statesync_client_context *const ctx, + monad_sync_done const msg) noexcept { MONAD_ASSERT(msg.success); @@ -155,7 +156,8 @@ void monad_statesync_client_handle_done( } } -bool monad_statesync_client_finalize(monad_statesync_client_context *const ctx) +bool monad_statesync_client_finalize( + monad_statesync_client_context *const ctx) noexcept { auto const &tgrt = ctx->tgrt; MONAD_ASSERT(tgrt.number != INVALID_BLOCK_NUM); @@ -222,7 +224,7 @@ bool monad_statesync_client_finalize(monad_statesync_client_context *const ctx) } void monad_statesync_client_context_destroy( - monad_statesync_client_context *const ctx) + monad_statesync_client_context *const ctx) noexcept { delete ctx; } diff --git a/category/statesync/statesync_client.h b/category/statesync/statesync_client.h index 49364ce47..e308dfed9 100644 --- a/category/statesync/statesync_client.h +++ b/category/statesync/statesync_client.h @@ -15,6 +15,7 @@ #pragma once +#include #include #ifdef __cplusplus @@ -31,32 +32,37 @@ struct monad_statesync_client_context *monad_statesync_client_context_create( char const *const *dbname_paths, size_t len, unsigned sq_thread_cpu, struct monad_statesync_client *, void (*statesync_send_request)( - struct monad_statesync_client *, struct monad_sync_request)); + struct monad_statesync_client *, + struct monad_sync_request)) MONAD_NOEXCEPT; -uint8_t monad_statesync_client_prefix_bytes(); +uint8_t monad_statesync_client_prefix_bytes() MONAD_NOEXCEPT; -size_t monad_statesync_client_prefixes(); +size_t monad_statesync_client_prefixes() MONAD_NOEXCEPT; bool monad_statesync_client_has_reached_target( - struct monad_statesync_client_context const *); + struct monad_statesync_client_context const *) MONAD_NOEXCEPT; void monad_statesync_client_handle_new_peer( - struct monad_statesync_client_context *, uint64_t prefix, uint32_t version); + struct monad_statesync_client_context *, uint64_t prefix, + uint32_t version) MONAD_NOEXCEPT; void monad_statesync_client_handle_target( - struct monad_statesync_client_context *, unsigned char const *, uint64_t); + struct monad_statesync_client_context *, unsigned char const *, + uint64_t) MONAD_NOEXCEPT; bool monad_statesync_client_handle_upsert( struct monad_statesync_client_context *, uint64_t prefix, - enum monad_sync_type, unsigned char const *, uint64_t); + enum monad_sync_type, unsigned char const *, uint64_t) MONAD_NOEXCEPT; void monad_statesync_client_handle_done( - struct monad_statesync_client_context *, struct monad_sync_done); + struct monad_statesync_client_context *, + struct monad_sync_done) MONAD_NOEXCEPT; -bool monad_statesync_client_finalize(struct monad_statesync_client_context *); +bool monad_statesync_client_finalize(struct monad_statesync_client_context *) + MONAD_NOEXCEPT; void monad_statesync_client_context_destroy( - struct monad_statesync_client_context *); + struct monad_statesync_client_context *) MONAD_NOEXCEPT; #ifdef __cplusplus } diff --git a/category/statesync/statesync_server.cpp b/category/statesync/statesync_server.cpp index fe6c49eef..10cd25837 100644 --- a/category/statesync/statesync_server.cpp +++ b/category/statesync/statesync_server.cpp @@ -351,7 +351,7 @@ struct monad_statesync_server *monad_statesync_server_create( unsigned char const *v1, uint64_t size1, unsigned char const *v2, uint64_t size2), void (*statesync_server_send_done)( - monad_statesync_server_network *, struct monad_sync_done)) + monad_statesync_server_network *, struct monad_sync_done)) noexcept { return new monad_statesync_server(monad_statesync_server{ .context = ctx, @@ -361,7 +361,8 @@ struct monad_statesync_server *monad_statesync_server_create( .statesync_server_send_done = statesync_server_send_done}); } -void monad_statesync_server_run_once(struct monad_statesync_server *const sync) +void monad_statesync_server_run_once( + struct monad_statesync_server *const sync) noexcept { unsigned char buf[sizeof(monad_sync_request)]; if (sync->statesync_server_recv(sync->net, buf, 1) != 1) { @@ -382,7 +383,7 @@ void monad_statesync_server_run_once(struct monad_statesync_server *const sync) monad_statesync_server_handle_request(sync, rq); } -void monad_statesync_server_destroy(monad_statesync_server *const sync) +void monad_statesync_server_destroy(monad_statesync_server *const sync) noexcept { delete sync; } diff --git a/category/statesync/statesync_server.h b/category/statesync/statesync_server.h index 1aee73b2f..40172e6c4 100644 --- a/category/statesync/statesync_server.h +++ b/category/statesync/statesync_server.h @@ -15,6 +15,7 @@ #pragma once +#include #include struct monad_statesync_server; @@ -31,8 +32,11 @@ struct monad_statesync_server *monad_statesync_server_create( unsigned char const *v1, uint64_t size1, unsigned char const *v2, uint64_t size2), void (*statesync_server_send_done)( - struct monad_statesync_server_network *, struct monad_sync_done)); + struct monad_statesync_server_network *, + struct monad_sync_done)) MONAD_NOEXCEPT; -void monad_statesync_server_run_once(struct monad_statesync_server *); +void monad_statesync_server_run_once(struct monad_statesync_server *) + MONAD_NOEXCEPT; -void monad_statesync_server_destroy(struct monad_statesync_server *); +void monad_statesync_server_destroy(struct monad_statesync_server *) + MONAD_NOEXCEPT; diff --git a/category/statesync/statesync_version.cpp b/category/statesync/statesync_version.cpp index 72dc3ae44..8496468ce 100644 --- a/category/statesync/statesync_version.cpp +++ b/category/statesync/statesync_version.cpp @@ -19,12 +19,12 @@ constexpr uint32_t MONAD_STATESYNC_VERSION = 1; -uint32_t monad_statesync_version() +uint32_t monad_statesync_version() noexcept { return MONAD_STATESYNC_VERSION; } -bool monad_statesync_client_compatible(uint32_t const version) +bool monad_statesync_client_compatible(uint32_t const version) noexcept { return version <= MONAD_STATESYNC_VERSION && version >= 1; } diff --git a/category/statesync/statesync_version.h b/category/statesync/statesync_version.h index db4985305..04b0e7b1e 100644 --- a/category/statesync/statesync_version.h +++ b/category/statesync/statesync_version.h @@ -15,6 +15,8 @@ #pragma once +#include + #include #ifdef __cplusplus @@ -22,9 +24,9 @@ extern "C" { #endif -uint32_t monad_statesync_version(); +uint32_t monad_statesync_version() MONAD_NOEXCEPT; -bool monad_statesync_client_compatible(uint32_t version); +bool monad_statesync_client_compatible(uint32_t version) MONAD_NOEXCEPT; #ifdef __cplusplus } diff --git a/cmd/monad/main.cpp b/cmd/monad/main.cpp index afe5a878b..16b0c9dc2 100644 --- a/cmd/monad/main.cpp +++ b/cmd/monad/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -86,27 +87,6 @@ void signal_handler(int) stop = 1; } -std::terminate_handler cxx_runtime_terminate_handler; - -extern "C" void monad_stack_backtrace_capture_and_print( - char *buffer, size_t size, int fd, unsigned indent, - bool print_async_unsafe_info); - -void backtrace_terminate_handler() -{ - char buffer[16384]; - monad_stack_backtrace_capture_and_print( - buffer, - sizeof(buffer), - STDERR_FILENO, - /*indent*/ 3, - /*print_async_unsafe_info*/ true); - - // Now that we've printed the trace, delegate the actual termination to the - // handler originally installed by the C++ runtime support library - cxx_runtime_terminate_handler(); -} - MONAD_ANONYMOUS_NAMESPACE_END using namespace monad; @@ -114,8 +94,8 @@ namespace fs = std::filesystem; int main(int const argc, char const *argv[]) try { - cxx_runtime_terminate_handler = std::get_terminate(); - std::set_terminate(backtrace_terminate_handler); + // Install custom terminate handler that prints exception info and backtrace + monad_set_terminate_handler(); CLI::App cli{"monad"}; cli.option_defaults()->always_capture_default();