components/gnuplot/patches/wxWidgets3-exit.patch
author Petr Sumbera <petr.sumbera@oracle.com>
Thu, 05 May 2016 07:38:15 -0700
changeset 5994 af9925efa591
permissions -rw-r--r--
23094118 Upgrade wxwidgets to 3.0.2 or newer

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))