diff options
Diffstat (limited to 'app/signals.c')
-rw-r--r-- | app/signals.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/app/signals.c b/app/signals.c new file mode 100644 index 0000000..92fd266 --- /dev/null +++ b/app/signals.c @@ -0,0 +1,186 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <signal.h> + +#include <gio/gio.h> + +#include "libgimpbase/gimpbase.h" + +#include "core/core-types.h" + +#include "core/gimp.h" + +#include "errors.h" +#include "signals.h" + +#ifdef G_OS_WIN32 +#ifdef HAVE_EXCHNDL +#include <windows.h> +#include <time.h> +#include <exchndl.h> + +static LPTOP_LEVEL_EXCEPTION_FILTER g_prevExceptionFilter = NULL; + +static LONG WINAPI gimp_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo); +#endif + +#else + +static void gimp_sigfatal_handler (gint sig_num) G_GNUC_NORETURN; + +#endif + + +void +gimp_init_signal_handlers (gchar **backtrace_file) +{ + time_t t; + gchar *filename; + gchar *dir; + +#ifdef G_OS_WIN32 + /* This has to be the non-roaming directory (i.e., the local + directory) as backtraces correspond to the binaries on this + system. */ + dir = g_build_filename (g_get_user_data_dir (), + GIMPDIR, GIMP_USER_VERSION, "CrashLog", + NULL); +#else + dir = g_build_filename (gimp_directory (), "CrashLog", NULL); +#endif + + time (&t); + filename = g_strdup_printf ("%s-crash-%" G_GUINT64_FORMAT ".txt", + PACKAGE_NAME, (guint64) t); + *backtrace_file = g_build_filename (dir, filename, NULL); + g_free (filename); + g_free (dir); + +#ifdef G_OS_WIN32 + /* Use Dr. Mingw (dumps backtrace on crash) if it is available. Do + * nothing otherwise on Win32. + * The user won't get any stack trace from glib anyhow. + * Without Dr. MinGW, It's better to let Windows inform about the + * program error, and offer debugging (if the user has installed MSVC + * or some other compiler that knows how to install itself as a + * handler for program errors). + */ + +#ifdef HAVE_EXCHNDL + /* Order is very important here. We need to add our signal handler + * first, then run ExcHndlInit() which will add its own handler, so + * that ExcHnl's handler runs first since that's in FILO order. + */ + if (! g_prevExceptionFilter) + g_prevExceptionFilter = SetUnhandledExceptionFilter (gimp_sigfatal_handler); + + ExcHndlInit (); + ExcHndlSetLogFileNameA (*backtrace_file); + +#endif /* HAVE_EXCHNDL */ + +#else + + /* Handle fatal signals */ + + /* these are handled by gimp_terminate() */ + gimp_signal_private (SIGHUP, gimp_sigfatal_handler, 0); + gimp_signal_private (SIGINT, gimp_sigfatal_handler, 0); + gimp_signal_private (SIGQUIT, gimp_sigfatal_handler, 0); + gimp_signal_private (SIGTERM, gimp_sigfatal_handler, 0); + + /* these are handled by gimp_fatal_error() */ + gimp_signal_private (SIGABRT, gimp_sigfatal_handler, 0); + gimp_signal_private (SIGBUS, gimp_sigfatal_handler, 0); + gimp_signal_private (SIGSEGV, gimp_sigfatal_handler, 0); + gimp_signal_private (SIGFPE, gimp_sigfatal_handler, 0); + + /* Ignore SIGPIPE because plug_in.c handles broken pipes */ + gimp_signal_private (SIGPIPE, SIG_IGN, 0); + + /* Restart syscalls on SIGCHLD */ + gimp_signal_private (SIGCHLD, SIG_DFL, SA_RESTART); + +#endif /* G_OS_WIN32 */ +} + + +#ifdef G_OS_WIN32 + +#ifdef HAVE_EXCHNDL +static LONG WINAPI +gimp_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo) +{ + EXCEPTION_RECORD *er; + int fatal; + + if (pExceptionInfo == NULL || + pExceptionInfo->ExceptionRecord == NULL) + return EXCEPTION_CONTINUE_SEARCH; + + er = pExceptionInfo->ExceptionRecord; + fatal = I_RpcExceptionFilter (er->ExceptionCode); + + /* IREF() returns EXCEPTION_CONTINUE_SEARCH for fatal exceptions */ + if (fatal == EXCEPTION_CONTINUE_SEARCH) + { + /* Just in case, so that we don't loop or anything similar, just + * re-establish previous handler. + */ + SetUnhandledExceptionFilter (g_prevExceptionFilter); + + /* Now process the exception. */ + gimp_fatal_error ("unhandled exception"); + } + + if (g_prevExceptionFilter && g_prevExceptionFilter != gimp_sigfatal_handler) + return g_prevExceptionFilter (pExceptionInfo); + else + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + +#else + +/* gimp core signal handler for fatal signals */ + +static void +gimp_sigfatal_handler (gint sig_num) +{ + switch (sig_num) + { + case SIGHUP: + case SIGINT: + case SIGQUIT: + case SIGTERM: + gimp_terminate (g_strsignal (sig_num)); + break; + + case SIGABRT: + case SIGBUS: + case SIGSEGV: + case SIGFPE: + default: + gimp_fatal_error (g_strsignal (sig_num)); + break; + } +} + +#endif /* G_OS_WIN32 */ |