/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * 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 . */ #include "config.h" #include #include #include "libpikabase/pikabase.h" #include "core/core-types.h" #include "core/pika.h" #include "errors.h" #include "signals.h" #ifdef G_OS_WIN32 #ifdef HAVE_EXCHNDL #include #include #include static LPTOP_LEVEL_EXCEPTION_FILTER g_prevExceptionFilter = NULL; static LONG WINAPI pika_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo); #endif #else static void pika_sigfatal_handler (gint sig_num) G_GNUC_NORETURN; #endif void pika_init_signal_handlers (gchar **backtrace_file) { time_t t; gchar *filename; gchar *dir; #if defined (G_OS_WIN32) && defined (HAVE_EXCHNDL) wchar_t *backtrace_file_utf16; #endif #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 (), PIKADIR, PIKA_USER_VERSION, "CrashLog", NULL); #else dir = g_build_filename (pika_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 (pika_sigfatal_handler); ExcHndlInit (); if ((backtrace_file_utf16 = g_utf8_to_utf16 (*backtrace_file, -1, NULL, NULL, NULL))) { ExcHndlSetLogFileNameW (backtrace_file_utf16); g_free (backtrace_file_utf16); } #endif /* HAVE_EXCHNDL */ #else /* Handle fatal signals */ /* these are handled by pika_terminate() */ pika_signal_private (SIGHUP, pika_sigfatal_handler, 0); pika_signal_private (SIGINT, pika_sigfatal_handler, 0); pika_signal_private (SIGQUIT, pika_sigfatal_handler, 0); pika_signal_private (SIGTERM, pika_sigfatal_handler, 0); /* these are handled by pika_fatal_error() */ /* * MacOS has it's own crash handlers which end up fighting the * these Pika supplied handlers and leading to very hard to * deal with hangs (just get a spin dump) */ #ifndef PLATFORM_OSX pika_signal_private (SIGABRT, pika_sigfatal_handler, 0); pika_signal_private (SIGBUS, pika_sigfatal_handler, 0); pika_signal_private (SIGSEGV, pika_sigfatal_handler, 0); pika_signal_private (SIGFPE, pika_sigfatal_handler, 0); #endif /* Ignore SIGPIPE because plug_in.c handles broken pipes */ pika_signal_private (SIGPIPE, SIG_IGN, 0); /* Restart syscalls on SIGCHLD */ pika_signal_private (SIGCHLD, SIG_DFL, SA_RESTART); #endif /* G_OS_WIN32 */ } #ifdef G_OS_WIN32 #ifdef HAVE_EXCHNDL static LONG WINAPI pika_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. */ pika_fatal_error ("unhandled exception"); } if (g_prevExceptionFilter && g_prevExceptionFilter != pika_sigfatal_handler) return g_prevExceptionFilter (pExceptionInfo); else return EXCEPTION_CONTINUE_SEARCH; } #endif #else /* pika core signal handler for fatal signals */ static void pika_sigfatal_handler (gint sig_num) { switch (sig_num) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGTERM: pika_terminate (g_strsignal (sig_num)); break; case SIGABRT: case SIGBUS: case SIGSEGV: case SIGFPE: default: pika_fatal_error (g_strsignal (sig_num)); break; } } #endif /* G_OS_WIN32 */