Skip to content

Commit

Permalink
Merge pull request equinor#634 from mortalisk/more_signal_handling
Browse files Browse the repository at this point in the history
Restore previous abort handler if it was present
  • Loading branch information
mortalisk authored Jul 4, 2019
2 parents a319377 + 18a7753 commit 56f1330
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 20 deletions.
8 changes: 8 additions & 0 deletions lib/include/ert/util/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <stdarg.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>


#include <ert/util/ert_api_config.hpp>
Expand Down Expand Up @@ -387,6 +388,13 @@ typedef bool (walk_dir_callback_ftype) (const char * , /* The current director
CONTAINS_HEADER(size_t);
#undef CONTAINS_HEADER

/* Redefining sighandler_t in case it isn't defined (Windows).
This is harmless on other platforms. */
typedef void (*sighandler_t)(int);
/* When installing our abort handler, remeber if there was a previous one,
* so we can call that afterwards */
extern sighandler_t previous_abort_handler;

#ifdef _MSC_VER
#define util_abort(fmt , ...) util_abort__(__FILE__ , __func__ , __LINE__ , fmt , __VA_ARGS__)
#elif __GNUC__
Expand Down
25 changes: 17 additions & 8 deletions lib/util/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4405,12 +4405,17 @@ char * util_realloc_sprintf(char * s , const char * fmt , ...) {
The various signals can be found in: /usr/include/bits/signum.h
*/

sighandler_t previous_abort_handler = SIG_IGN;

void util_abort_signal(int signal) {
util_abort("Program received signal:%d\n" , signal);
void util_abort_signal(int the_signal) {
if (previous_abort_handler == SIG_IGN) {
signal(SIGABRT, SIG_DFL);
} else {
signal(SIGABRT, previous_abort_handler);
}
util_abort("Program received signal:%d\n" , the_signal);
}


void util_install_signals(void) {
#ifdef HAVE_SIGBUS
signal(SIGBUS , util_abort_signal);
Expand All @@ -4419,7 +4424,14 @@ void util_install_signals(void) {
signal(SIGSEGV , util_abort_signal); /* Segmentation violation, i.e. overwriting memory ... */
signal(SIGTERM , util_abort_signal); /* If killing the enkf program with SIGTERM (the default kill signal) you will get a backtrace.
Killing with SIGKILL (-9) will not give a backtrace.*/
signal(SIGABRT , util_abort_signal); /* Signal abort. */


sighandler_t previous_abort = signal(SIGABRT , util_abort_signal); /* Signal abort. */
if (previous_abort != util_abort_signal) {
/* Let previously installed abort handler (i.e. python faulthandler) be called in the end */
previous_abort_handler = previous_abort;
}

signal(SIGILL , util_abort_signal); /* Signal illegal instruction. */
signal(SIGFPE , util_abort_signal); /* Floating point exception */
}
Expand All @@ -4429,10 +4441,7 @@ void util_install_signals(void) {
have not been modified from the default state.
*/

static void update_signal( int signal_nr ) {
/* Redefining sighandler_t in case it isn't defined (Windows).
This is harmless on other platforms. */
typedef void (*sighandler_t)(int);
static void update_signal( int signal_nr) {

sighandler_t current_handler = signal(signal_nr , SIG_DFL);
if (current_handler == SIG_DFL)
Expand Down
19 changes: 14 additions & 5 deletions lib/util/util_abort_gnu.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,10 @@ static char* __abort_program_message;

void util_abort__(const char * file , const char * function , int line , const char * fmt , ...) {
util_abort_test_intercept( function );
pthread_mutex_lock( &__abort_mutex ); /* Abort before unlock() */
{
/* if we cannot lock, presumably we could not open a file and we are calling
* util_abort recursively */
int lock_status = pthread_mutex_trylock( &__abort_mutex );
if (lock_status == 0) {
char * filename = NULL;
FILE * abort_dump = NULL;

Expand Down Expand Up @@ -277,7 +279,7 @@ void util_abort__(const char * file , const char * function , int line , const c
addr2line; the call is based on util_spawn() which is
currently only available on POSIX.
*/
const bool include_backtrace = true;
const bool include_backtrace = (lock_status == 0);
if (include_backtrace) {
if (__abort_program_message != NULL) {
#if !defined(__GLIBC__)
Expand Down Expand Up @@ -313,10 +315,17 @@ void util_abort__(const char * file , const char * function , int line , const c
}
chmod(filename, 00644); // -rw-r--r--
free(filename);
pthread_mutex_unlock(&__abort_mutex);
} else {
/* Failure in util_abort. Print basic error message and exit. */
fprintf(stderr, "Error while handling error. Exiting. File: %s Function: %s, Line: %d\n", file, function, line);
fprintf(stderr , "Error message: ");
va_list ap;
va_start(ap , fmt);
vfprintf(stderr , fmt , ap);
va_end(ap);
}

pthread_mutex_unlock(&__abort_mutex);
signal(SIGABRT, SIG_DFL);
abort();
}

Expand Down
1 change: 0 additions & 1 deletion lib/util/util_abort_simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ void util_abort__(const char * file , const char * function , int line , const c
}
fprintf(stderr,"-----------------------------------------------------------------\n");

signal(SIGABRT , SIG_DFL);
fprintf(stderr , "Aborting ... \n");
assert(0);
abort();
Expand Down
5 changes: 2 additions & 3 deletions python/ecl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
alternative fails, the loader will try the default load behaviour
before giving up completely.
"""
import os
import os.path
import sys

Expand Down Expand Up @@ -135,8 +134,8 @@ def __init__(self, prototype, bind=True):
from .util.util import EclVersion
from .util.util import updateAbortSignals

if not os.getenv('ECL_SKIP_SIGNAL'):
updateAbortSignals( )

updateAbortSignals( )

def root():
"""
Expand Down
8 changes: 5 additions & 3 deletions python/ecl/util/util/install_abort_signals.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from ecl import EclPrototype

import os

def installAbortSignals():
install_signals()
if not os.getenv('ECL_SKIP_SIGNAL'):
install_signals()


def updateAbortSignals():
"""
Will install the util_abort_signal for all UNMODIFIED signals.
"""
update_signals()
if not os.getenv('ECL_SKIP_SIGNAL'):
update_signals()


install_signals = EclPrototype("void util_install_signals()")
Expand Down

0 comments on commit 56f1330

Please sign in to comment.