Fix handling of SIGSEGV and SIGABRT in nano_node (#3502)

The handling of SIGSEGV and SIGABRT did not have the desired effect of
generating stack traces of the source code that caused the signal.

That's because the signals were handled by the signal manager, which
first switches stack context to one that is safe to execute any code.
However, for SIGSEGV and SIGABRT we want to print the stacktrace of
the problem and therefore we cannot switch context.

So, I am setting the handling of SIGSEGV and SIGABRT to use the classic
signal function, like before the signal manager was introduced.
This commit is contained in:
dsiganos 2021-10-13 14:33:33 +01:00 committed by GitHub
commit 6063f5f011
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 15 deletions

View file

@ -49,14 +49,6 @@ void nano::signal_manager::register_signal_handler (int signum, std::function<vo
log (boost::str (boost::format ("Registered signal handler for signal %d") % signum));
}
std::function<void (int)> nano::signal_manager::get_debug_files_handler (void)
{
return [] (int) {
nano::dump_crash_stacktrace ();
nano::create_load_memory_address_files ();
};
}
void nano::signal_manager::base_handler (nano::signal_manager::signal_descriptor descriptor, const boost::system::error_code & error, int signum)
{
if (!error)

View file

@ -33,9 +33,6 @@ public:
*/
void register_signal_handler (int signum, std::function<void (int)> handler, bool repeat);
/** returns a signal handler that prints a stacktrace and creates some debug files */
std::function<void (int)> get_debug_files_handler (void);
private:
struct signal_descriptor final
{

View file

@ -17,6 +17,16 @@
namespace
{
void nano_abort_signal_handler (int signum)
{
// create some debugging log files
nano::dump_crash_stacktrace ();
nano::create_load_memory_address_files ();
// re-raise signal to call the default handler and exit
raise (signum);
}
volatile sig_atomic_t sig_int_or_term = 0;
constexpr std::size_t OPEN_FILE_DESCRIPTORS_LIMIT = 16384;
@ -39,10 +49,14 @@ static void load_and_set_bandwidth_params (std::shared_ptr<nano::node> const & n
void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::node_flags const & flags)
{
// Override segmentation fault and aborting.
nano::signal_manager sigman;
sigman.register_signal_handler (SIGSEGV, sigman.get_debug_files_handler (), false);
sigman.register_signal_handler (SIGABRT, sigman.get_debug_files_handler (), false);
// We catch signal SIGSEGV and SIGABRT not via the signal manager because we want these signal handlers
// to be executed in the stack of the code that caused the signal, so we can dump the stacktrace.
struct sigaction sa = {};
sa.sa_handler = nano_abort_signal_handler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_RESETHAND;
sigaction (SIGSEGV, &sa, NULL);
sigaction (SIGABRT, &sa, NULL);
boost::filesystem::create_directories (data_path);
boost::system::error_code error_chmod;
@ -155,6 +169,8 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
sig_int_or_term = 1;
};
nano::signal_manager sigman;
// keep trapping Ctrl-C to avoid a second Ctrl-C interrupting tasks started by the first
sigman.register_signal_handler (SIGINT, &nano::signal_handler, true);