From fa02a2c64f5fcaaceff34cea2bd02c5e558c63ca Mon Sep 17 00:00:00 2001 From: Jehan Date: Wed, 4 Apr 2018 18:04:34 +0200 Subject: [PATCH] libgimp: add an exception handler for Windows. Drmingw already added its own exception handler which generates crash traces in a text file, for plug-ins as well. This additional handler is run after Drmingw handler and allows us to do things on our own, and in particular we could display the content of the debug traces. Right now it simply prints these to stderr, which actually won't be of much use on Win32, first because the console is deactivated on stable releases, also because after tests, it doesn't look like even running GIMP from cmd outputs to console either. We currently don't use the same debug dialog as the core on purpose, because we don't want everyone to send us traces for every unmaintained third party plug-ins out there. But we should definitely allow easier trace possibilities at some point, first to improve/debug our own core plug-ins, and also to help third party plug-in developers! So this commit is not making visible changes yet but is actually a first step towards these debugging goals. --- libgimp/gimp.c | 80 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/libgimp/gimp.c b/libgimp/gimp.c index f42087b3ce..75ec23cad4 100644 --- a/libgimp/gimp.c +++ b/libgimp/gimp.c @@ -167,7 +167,11 @@ static void gimp_fatal_func (const gchar *log_domain, GLogLevelFlags flags, const gchar *message, gpointer data); -#ifndef G_OS_WIN32 +#ifdef G_OS_WIN32 +#ifdef HAVE_EXCHNDL +static LONG WINAPI gimp_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo); +#endif +#else static void gimp_plugin_sigfatal_handler (gint sig_num); #endif static gboolean gimp_plugin_io_error_handler (GIOChannel *channel, @@ -193,8 +197,13 @@ static void gimp_set_pdb_error (const GimpParam *return_vals, gint n_return_vals); -static GIOChannel *_readchannel = NULL; -GIOChannel *_writechannel = NULL; +#if defined G_OS_WIN32 && defined HAVE_EXCHNDL +static LPTOP_LEVEL_EXCEPTION_FILTER _prevExceptionFilter = NULL; +static gchar *plug_in_backtrace_path = NULL; +#endif + +static GIOChannel *_readchannel = NULL; +GIOChannel *_writechannel = NULL; #ifdef USE_WIN32_SHM static HANDLE shm_handle; @@ -332,10 +341,9 @@ gimp_main (const GimpPlugInInfo *info, #ifdef HAVE_EXCHNDL /* Use Dr. Mingw (dumps backtrace on crash) if it is available. */ { - time_t t; - gchar *filename; - gchar *dir; - gchar *path; + time_t t; + gchar *filename; + gchar *dir; /* This has to be the non-roaming directory (i.e., the local directory) as backtraces correspond to the binaries on this @@ -349,14 +357,18 @@ gimp_main (const GimpPlugInInfo *info, time (&t); filename = g_strdup_printf ("%s-crash-%" G_GUINT64_FORMAT ".txt", g_get_prgname(), t); - path = g_build_filename (dir, filename, NULL); + plug_in_backtrace_path = g_build_filename (dir, filename, NULL); g_free (filename); g_free (dir); - ExcHndlInit (); - ExcHndlSetLogFileNameA (path); + /* Similar to core crash handling in app/signals.c, the order here + * is very important! + */ + if (! _prevExceptionFilter) + _prevExceptionFilter = SetUnhandledExceptionFilter (gimp_plugin_sigfatal_handler); - g_free (path); + ExcHndlInit (); + ExcHndlSetLogFileNameA (plug_in_backtrace_path); } #endif @@ -672,6 +684,11 @@ gimp_quit (void) { gimp_close (); +#if defined G_OS_WIN32 && defined HAVE_EXCHNDL + if (plug_in_backtrace_path) + g_free (plug_in_backtrace_path); +#endif + exit (EXIT_SUCCESS); } @@ -1986,7 +2003,46 @@ gimp_fatal_func (const gchar *log_domain, */ } -#ifndef G_OS_WIN32 +#ifdef G_OS_WIN32 + +#ifdef HAVE_EXCHNDL +static LONG WINAPI +gimp_plugin_sigfatal_handler (PEXCEPTION_POINTERS pExceptionInfo) +{ + g_printerr ("%s: fatal error\n", progname); + + SetUnhandledExceptionFilter (_prevExceptionFilter); + + /* For simplicity, do not make a difference between QUERY and ALWAYS + * on Windows (at least not for now). + */ + if (stack_trace_mode != GIMP_STACK_TRACE_NEVER && + g_file_test (plug_in_backtrace_path, G_FILE_TEST_IS_REGULAR)) + { + FILE *stream; + guchar buffer[256]; + size_t read_len; + + stream = fopen (plug_in_backtrace_path, "r"); + do + { + /* Just read and output directly the file content. */ + read_len = fread (buffer, 1, sizeof (buffer) - 1, stream); + buffer[read_len] = '\0'; + g_printerr ("%s", buffer); + } + while (read_len); + fclose (stream); + } + + if (_prevExceptionFilter && _prevExceptionFilter != gimp_plugin_sigfatal_handler) + return _prevExceptionFilter (pExceptionInfo); + else + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + +#else static void gimp_plugin_sigfatal_handler (gint sig_num) {