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();