Following commit was applied on Gnuplot 4.6.0. It avoids core dump on exit with wxWidgets 3.0.
It can be removed with Gnuplot update to version 5.0 or later.
https://github.com/gnuplot/gnuplot/commit/40d8c736f742f4c19cc4b5b3b3dc6552c220ae12
From 40d8c736f742f4c19cc4b5b3b3dc6552c220ae12 Mon Sep 17 00:00:00 2001
From: sfeam <sfeam>
Date: Fri, 25 Oct 2013 04:45:22 +0000
Subject: [PATCH] Add private handlers gp_exit() and gp_atexit()
diff --git a/src/command.c b/src/command.c
index 2c697ae..8662db1 100644
--- a/src/command.c
+++ b/src/command.c
@@ -890,7 +890,7 @@ exit_command()
{
/* If the command is "exit gnuplot" then do so */
if (equals(c_token+1,"gnuplot"))
- exit(0);
+ gp_exit(EXIT_SUCCESS);
/* else graphics will be tidied up in main */
command_exit_status = 1;
@@ -2269,7 +2269,7 @@ void
done(int status)
{
term_reset();
- exit(status);
+ gp_exit(status);
}
/* please note that the vms version of read_line doesn't support variable line
diff --git a/src/plot.c b/src/plot.c
index 96266b5..de3e24a 100644
--- a/src/plot.c
+++ b/src/plot.c
@@ -432,7 +432,7 @@ main(int argc, char **argv)
/* reset the terminal when exiting */
/* this is done through gp_atexit so that other terminal functions
* can be registered to be executed before the terminal is reset. */
- GP_ATEXIT(term_reset);
+ gp_atexit(term_reset);
# if defined(_Windows) && ! defined(WGP_CONSOLE)
interactive = TRUE;
@@ -569,7 +569,7 @@ main(int argc, char **argv)
* In case you don't have one of these functions, or you don't
* want to use them, 'write_history()' is called directly.
*/
- GP_ATEXIT(wrapper_for_write_history);
+ gp_atexit(wrapper_for_write_history);
#endif /* GNUPLOT_HISTORY */
fprintf(stderr, "\nTerminal type set to '%s'\n", term->name);
@@ -611,7 +611,7 @@ main(int argc, char **argv)
#endif /* VMS */
if (!interactive && !noinputfiles) {
term_reset();
- exit(EXIT_FAILURE); /* exit on non-interactive error */
+ gp_exit(EXIT_FAILURE); /* exit on non-interactive error */
}
}
@@ -642,12 +642,13 @@
--argc; ++argv;
if (argc <= 0) {
fprintf(stderr, "syntax: gnuplot -e \"commands\"\n");
- return 0;
+ gp_exit(EXIT_FAILURE);
}
do_string(*argv);
} else {
load_file(loadpath_fopen(*argv, "r"), gp_strdup(*argv), FALSE);
+ gp_exit(EXIT_SUCCESS);
}
}
#ifdef _Windows
@@ -674,6 +674,10 @@ main(int argc, char **argv)
/* HBB 20040223: Not all compilers like exit() to end main() */
/* exit(exit_status); */
+#if ! defined(_Windows)
+ /* Windows does the cleanup later */
+ gp_exit_cleanup();
+#endif
return exit_status;
}
diff --git a/src/stdfn.c b/src/stdfn.c
index 14526ca..914c7c1 100644
--- a/src/stdfn.c
+++ b/src/stdfn.c
@@ -384,6 +384,80 @@ char * gp_basename(char *path)
return path;
}
+#ifdef HAVE_ATEXIT
+# define GP_ATEXIT(x) atexit((x))
+#elif defined(HAVE_ON_EXIT)
+# define GP_ATEXIT(x) on_exit((x),0)
+#else
+# define GP_ATEXIT(x) /* you lose */
+#endif
+
+struct EXIT_HANDLER {
+ void (*function)(void);
+ struct EXIT_HANDLER* next;
+};
+
+static struct EXIT_HANDLER* exit_handlers = NULL;
+
+/* Calls the cleanup functions registered using gp_atexit().
+ * Normally gnuplot should be exited using gp_exit(). In some cases, this is not
+ * possible (notably when returning from main(), where some compilers get
+ * confused because they expect a return statement at the very end. In that
+ * case, gp_exit_cleanup() should be called before the return statement.
+ */
+void gp_exit_cleanup(void)
+{
+ /* Call exit handlers registered using gp_atexit(). This is used instead of
+ * normal atexit-handlers, because some libraries (notably Qt) seem to have
+ * problems with the destruction order when some objects are only destructed
+ * on atexit(3). Circumvent this problem by calling the gnuplot
+ * atexit-handlers, before any global destructors are run.
+ */
+ while (exit_handlers) {
+ struct EXIT_HANDLER* handler = exit_handlers;
+ (*handler->function)();
+ /* note: assumes that function above has not called gp_atexit() */
+ exit_handlers = handler->next;
+ free(handler);
+ }
+}
+
+/* Called from exit(3). Verifies that all exit handlers have already been
+ * called.
+ */
+static void debug_exit_handler(void)
+{
+ if (exit_handlers) {
+ fprintf(stderr, "Gnuplot not exited using gp_exit(). Exit handlers may"
+ "not work correctly!\n");
+ gp_exit_cleanup();
+ }
+}
+
+/* Gnuplot replacement for atexit(3) */
+void gp_atexit(void (*function)(void))
+{
+ /* Register new handler */
+ static bool debug_exit_handler_registered = false;
+ struct EXIT_HANDLER* new_handler = (struct EXIT_HANDLER*) malloc(sizeof(struct EXIT_HANDLER));
+ new_handler->function = function;
+ new_handler->next = exit_handlers;
+ exit_handlers = new_handler;
+
+ if (!debug_exit_handler_registered) {
+ GP_ATEXIT(debug_exit_handler);
+ debug_exit_handler_registered = true;
+ }
+}
+
+/* Gnuplot replacement for exit(3). Calls the functions registered using
+ * gp_atexit(). Always use this function instead of exit(3)!
+ */
+void gp_exit(int status)
+{
+ gp_exit_cleanup();
+ exit(status);
+}
#if !defined(HAVE_DIRENT_H) && defined(WIN32) && (!defined(__WATCOMC__))
/* BM: OpenWatcom has dirent functions in direct.h!*/
diff --git a/src/stdfn.h b/src/stdfn.h
index 9b2be3d..1224f57 100644
--- a/src/stdfn.h
+++ b/src/stdfn.h
@@ -370,13 +370,21 @@ size_t strnlen __PROTO((const char *str, size_t n));
# define GP_SLEEP(delay) sleep ((unsigned int) (delay+0.5))
#endif
-#ifdef HAVE_ATEXIT
-# define GP_ATEXIT(x) atexit((x))
-#elif defined(HAVE_ON_EXIT)
-# define GP_ATEXIT(x) on_exit((x),0)
-#else
-# define GP_ATEXIT(x) /* you lose */
-#endif
+/* Gnuplot replacement for atexit(3) */
+void gp_atexit __PROTO((void (*function)(void)));
+
+/* Gnuplot replacement for exit(3). Calls the functions registered using
+ * gp_atexit(). Always use this function instead of exit(3)!
+ */
+void gp_exit __PROTO((int status));
+
+/* Calls the cleanup functions registered using gp_atexit().
+ * Normally gnuplot should be exited using gp_exit(). In some cases, this is not
+ * possible (notably when returning from main(), where some compilers get
+ * confused because they expect a return statement at the very end. In that
+ * case, gp_exit_cleanup() should be called before the return statement.
+ */
+void gp_exit_cleanup __PROTO((void));
char * gp_basename __PROTO((char *path));
diff --git a/src/wxterminal/gp_cairo.c b/src/wxterminal/gp_cairo.c
index cc5a54a..35227fd 100644
--- a/src/wxterminal/gp_cairo.c
+++ b/src/wxterminal/gp_cairo.c
@@ -1724,7 +1724,7 @@
if (cairo_status (plot->cr)) {
printf("Cairo is unhappy: %s\n",
cairo_status_to_string (cairo_status (plot->cr)));
- exit(0);
+ gp_exit(EXIT_FAILURE);
}
cairo_set_source_rgb(plot->cr, plot->background.r, plot->background.g, plot->background.b);
cairo_paint(plot->cr);
@@ -1735,7 +1735,7 @@
if (cairo_status (plot->cr)) {
printf("Cairo is unhappy: %s\n",
cairo_status_to_string (cairo_status (plot->cr)));
- exit(0);
+ gp_exit(EXIT_FAILURE);
}
cairo_set_source_rgba(plot->cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint(plot->cr);
diff --git a/src/wxterminal/gp_cairo_helpers.c b/src/wxterminal/gp_cairo_helpers.c
index 76f773c..eb38f65 100644
--- a/src/wxterminal/gp_cairo_helpers.c
+++ b/src/wxterminal/gp_cairo_helpers.c
@@ -61,7 +61,7 @@ unsigned int * gp_cairo_helper_coordval_to_chars(coordval* image, int M, int N,
/* cairo image buffer, upper bits are alpha, then r, g and b
* Depends on endianess */
image255 = (unsigned int*) malloc(M*N*sizeof(unsigned int));
- if (!image255) { fprintf(stderr,"cairo terminal: out of memory!\n"); exit(-1);}
+ if (!image255) { fprintf(stderr,"cairo terminal: out of memory!\n"); gp_exit(EXIT_FAILURE);}
image255copy = image255;
/* TrueColor 24-bit plot->color mode */
diff --git a/src/wxterminal/wxt_gui.cpp b/src/wxterminal/wxt_gui.cpp
index 3f6cb53..105340b 100644
--- a/src/wxterminal/wxt_gui.cpp
+++ b/src/wxterminal/wxt_gui.cpp
@@ -1566,7 +1566,7 @@
if (!wxInitialize()) {
fprintf(stderr,"Failed to initialize wxWidgets.\n");
wxt_abort_init = true;
- return;
+ gp_exit(EXIT_FAILURE);
}
/* app initialization */
@@ -1600,7 +1600,7 @@ void wxt_init()
term_interlock = (void *)wxt_init;
/* register call for "persist" effect and cleanup */
- GP_ATEXIT(wxt_atexit);
+ gp_atexit(wxt_atexit);
}
wxt_sigint_check();
--- a/term/be.trm
+++ b/term/be.trm
@@ -165,7 +165,7 @@ BE_args(int argc, char *argv[])
if (!xargv) {
fputs ("not enough memory to copy argv - quitting\n", stderr);
- exit (EXIT_FAILURE);
+ gp_exit (EXIT_FAILURE);
}
/* We make a copy of the argument vector because
@@ -231,7 +231,7 @@ BE_init()
execvp(BE_command, optvec);
/* if we get here, something went wrong */
perror("exec failed");
- exit(1);
+ gp_exit(EXIT_FAILURE);
}
/* parent */
close(fdes[0]); /* read end of pipe */
@@ -239,7 +239,7 @@ BE_init()
} {
static int been_here = 0;
if (!been_here) {
- atexit(BE_atexit);
+ gp_atexit(BE_atexit);
been_here = 1;
}
}
diff --git a/term/x11.trm b/term/x11.trm
index b0c5d1c..1e68684 100644
--- a/term/x11.trm
+++ b/term/x11.trm
@@ -1004,7 +1004,7 @@ X11_init()
fprintf(stderr,"Expected X11 driver: %s\n",X11_full_command_path);
perror("Exec failed");
fprintf(stderr,"See 'help x11' for more details\n");
- exit(EXIT_FAILURE);
+ gp_exit(EXIT_FAILURE);
}
/* parent */
# ifdef PIPE_IPC
@@ -1037,7 +1037,7 @@ X11_init()
}
if (!been_here) {
- GP_ATEXIT(X11_atexit);
+ gp_atexit(X11_atexit);
been_here++;
}
X11_send_endianess();
@@ -1101,7 +1101,7 @@ X11_reset()
#define BEFORE_GRAPHICS \
if (!(X11_ipc = fopen(X11_tmp0, "w"))) { \
- perror(X11_tmp0); system(X11_shutdown); exit(1); \
+ perror(X11_tmp0); system(X11_shutdown); gp_exit(EXIT_FAILURE); \
}
#define AFTER_TEXT \
@@ -1229,7 +1229,7 @@ X11_init()
{
static int been_here = 0;
if (!been_here) {
- GP_ATEXIT(X11_atexit);
+ gp_atexit(X11_atexit);
been_here = 1;
}
}
@@ -1252,7 +1252,7 @@ do { \
} \
status = sys$qiow(0, X11_channel, IO$_WRITEVBLK, &iosb, 0, 0, buffer, strlen(buffer), 0, 0, 0, 0); \
if ((status & SS$_NORMAL) == SS$_NORMAL) status = iosb.stat; \
- if((status & SS$_NORMAL) != SS$_NORMAL) exit(status); \
+ if((status & SS$_NORMAL) != SS$_NORMAL) gp_exit(status); \
} while (0)
#define PRINT0(fmt) GO((buffer, fmt))