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.
This commit is contained in:
Jehan 2018-04-04 18:04:34 +02:00
parent 76bce77d09
commit fa02a2c64f
1 changed files with 68 additions and 12 deletions

View File

@ -167,7 +167,11 @@ static void gimp_fatal_func (const gchar *log_domain,
GLogLevelFlags flags, GLogLevelFlags flags,
const gchar *message, const gchar *message,
gpointer data); 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); static void gimp_plugin_sigfatal_handler (gint sig_num);
#endif #endif
static gboolean gimp_plugin_io_error_handler (GIOChannel *channel, 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); gint n_return_vals);
static GIOChannel *_readchannel = NULL; #if defined G_OS_WIN32 && defined HAVE_EXCHNDL
GIOChannel *_writechannel = NULL; 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 #ifdef USE_WIN32_SHM
static HANDLE shm_handle; static HANDLE shm_handle;
@ -332,10 +341,9 @@ gimp_main (const GimpPlugInInfo *info,
#ifdef HAVE_EXCHNDL #ifdef HAVE_EXCHNDL
/* Use Dr. Mingw (dumps backtrace on crash) if it is available. */ /* Use Dr. Mingw (dumps backtrace on crash) if it is available. */
{ {
time_t t; time_t t;
gchar *filename; gchar *filename;
gchar *dir; gchar *dir;
gchar *path;
/* This has to be the non-roaming directory (i.e., the local /* This has to be the non-roaming directory (i.e., the local
directory) as backtraces correspond to the binaries on this directory) as backtraces correspond to the binaries on this
@ -349,14 +357,18 @@ gimp_main (const GimpPlugInInfo *info,
time (&t); time (&t);
filename = g_strdup_printf ("%s-crash-%" G_GUINT64_FORMAT ".txt", filename = g_strdup_printf ("%s-crash-%" G_GUINT64_FORMAT ".txt",
g_get_prgname(), t); 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 (filename);
g_free (dir); g_free (dir);
ExcHndlInit (); /* Similar to core crash handling in app/signals.c, the order here
ExcHndlSetLogFileNameA (path); * is very important!
*/
if (! _prevExceptionFilter)
_prevExceptionFilter = SetUnhandledExceptionFilter (gimp_plugin_sigfatal_handler);
g_free (path); ExcHndlInit ();
ExcHndlSetLogFileNameA (plug_in_backtrace_path);
} }
#endif #endif
@ -672,6 +684,11 @@ gimp_quit (void)
{ {
gimp_close (); 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); 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 static void
gimp_plugin_sigfatal_handler (gint sig_num) gimp_plugin_sigfatal_handler (gint sig_num)
{ {