aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorfurszy <matiasfurszyfer@protonmail.com>2023-05-20 10:51:17 -0300
committerfurszy <matiasfurszyfer@protonmail.com>2023-06-09 17:52:23 -0300
commit3b2c61e8198bcefb1c2343caff1d705951026cc4 (patch)
treec4ad99b748548d76a15ffaf32d9dad44c774e1ec /src
parent3c06926cf21dcca3074ef51506f556b2286c299b (diff)
downloadbitcoin-3b2c61e8198bcefb1c2343caff1d705951026cc4.tar.xz
Return EXIT_FAILURE on post-init fatal errors
It seems odd to return `EXIT_SUCCESS` when the node aborted execution due a fatal internal error or any post-init problem that triggers an unrequested shutdown. e.g. blocks or coins db I/O errors, disconnect block failure, failure during thread import (external blocks loading process error), among others. Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
Diffstat (limited to 'src')
-rw-r--r--src/bitcoind.cpp6
-rw-r--r--src/init.cpp4
-rw-r--r--src/init.h2
-rw-r--r--src/node/context.h3
-rw-r--r--src/node/interfaces.cpp2
-rw-r--r--src/shutdown.cpp7
-rw-r--r--src/shutdown.h4
7 files changed, 20 insertions, 8 deletions
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index aefb130e9c..8982d0a316 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -169,7 +169,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
// Set this early so that parameter interactions go to console
InitLogging(args);
InitParameterInteraction(args);
- if (!AppInitBasicSetup(args)) {
+ if (!AppInitBasicSetup(args, node.exit_status)) {
// InitError will have been called with detailed error, which ends up on console
return false;
}
@@ -238,6 +238,8 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
SetSyscallSandboxPolicy(SyscallSandboxPolicy::SHUTOFF);
if (fRet) {
WaitForShutdown();
+ } else {
+ node.exit_status = EXIT_FAILURE;
}
Interrupt(node);
Shutdown(node);
@@ -264,5 +266,5 @@ MAIN_FUNCTION
// Connect bitcoind signal handlers
noui_connect();
- return (AppInit(node, argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
+ return AppInit(node, argc, argv) ? node.exit_status.load() : EXIT_FAILURE;
}
diff --git a/src/init.cpp b/src/init.cpp
index e8c804b9a7..38e1dbb4a2 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -800,7 +800,7 @@ std::set<BlockFilterType> g_enabled_filter_types;
std::terminate();
};
-bool AppInitBasicSetup(const ArgsManager& args)
+bool AppInitBasicSetup(const ArgsManager& args, std::atomic<int>& exit_status)
{
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
@@ -814,7 +814,7 @@ bool AppInitBasicSetup(const ArgsManager& args)
// Enable heap terminate-on-corruption
HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0);
#endif
- if (!InitShutdownState()) {
+ if (!InitShutdownState(exit_status)) {
return InitError(Untranslated("Initializing wait-for-shutdown state failed."));
}
diff --git a/src/init.h b/src/init.h
index 8c5b2e77d3..fabb4f66d6 100644
--- a/src/init.h
+++ b/src/init.h
@@ -38,7 +38,7 @@ void InitParameterInteraction(ArgsManager& args);
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read.
*/
-bool AppInitBasicSetup(const ArgsManager& args);
+bool AppInitBasicSetup(const ArgsManager& args, std::atomic<int>& exit_status);
/**
* Initialization: parameter interaction.
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
diff --git a/src/node/context.h b/src/node/context.h
index 9532153cdb..91b68fa5bb 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -7,7 +7,9 @@
#include <kernel/context.h>
+#include <atomic>
#include <cassert>
+#include <cstdlib>
#include <functional>
#include <memory>
#include <vector>
@@ -65,6 +67,7 @@ struct NodeContext {
std::unique_ptr<CScheduler> scheduler;
std::function<void()> rpc_interruption_point = [] {};
std::unique_ptr<KernelNotifications> notifications;
+ std::atomic<int> exit_status{EXIT_SUCCESS};
//! Declare default constructor and destructor that are not inline, so code
//! instantiating the NodeContext struct doesn't need to #include class
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 6e39ccf34e..bf42167c2f 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -92,7 +92,7 @@ public:
uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override
{
- if (!AppInitBasicSetup(args())) return false;
+ if (!AppInitBasicSetup(args(), Assert(context())->exit_status)) return false;
if (!AppInitParameterInteraction(args(), /*use_syscall_sandbox=*/false)) return false;
m_context->kernel = std::make_unique<kernel::Context>();
diff --git a/src/shutdown.cpp b/src/shutdown.cpp
index 2fffc0663c..d70017d734 100644
--- a/src/shutdown.cpp
+++ b/src/shutdown.cpp
@@ -11,6 +11,7 @@
#include <logging.h>
#include <node/interface_ui.h>
+#include <util/check.h>
#include <util/tokenpipe.h>
#include <warnings.h>
@@ -20,6 +21,8 @@
#include <condition_variable>
#endif
+static std::atomic<int>* g_exit_status{nullptr};
+
bool AbortNode(const std::string& strMessage, bilingual_str user_message)
{
SetMiscWarning(Untranslated(strMessage));
@@ -28,6 +31,7 @@ bool AbortNode(const std::string& strMessage, bilingual_str user_message)
user_message = _("A fatal internal error occurred, see debug.log for details");
}
InitError(user_message);
+ Assert(g_exit_status)->store(EXIT_FAILURE);
StartShutdown();
return false;
}
@@ -44,8 +48,9 @@ static TokenPipeEnd g_shutdown_r;
static TokenPipeEnd g_shutdown_w;
#endif
-bool InitShutdownState()
+bool InitShutdownState(std::atomic<int>& exit_status)
{
+ g_exit_status = &exit_status;
#ifndef WIN32
std::optional<TokenPipe> pipe = TokenPipe::Make();
if (!pipe) return false;
diff --git a/src/shutdown.h b/src/shutdown.h
index 07a8315788..c119bee96f 100644
--- a/src/shutdown.h
+++ b/src/shutdown.h
@@ -8,13 +8,15 @@
#include <util/translation.h> // For bilingual_str
+#include <atomic>
+
/** Abort with a message */
bool AbortNode(const std::string& strMessage, bilingual_str user_message = bilingual_str{});
/** Initialize shutdown state. This must be called before using either StartShutdown(),
* AbortShutdown() or WaitForShutdown(). Calling ShutdownRequested() is always safe.
*/
-bool InitShutdownState();
+bool InitShutdownState(std::atomic<int>& exit_status);
/** Request shutdown of the application. */
void StartShutdown();