implementing segfault handler for plugin loading
authorThomas Vander Stichele <thomas@apestaart.org>
Mon, 15 Dec 2003 12:44:35 +0000 (12:44 +0000)
committerThomas Vander Stichele <thomas@apestaart.org>
Mon, 15 Dec 2003 12:44:35 +0000 (12:44 +0000)
Original commit message from CVS:
implementing segfault handler for plugin loading

ChangeLog
gst/gst.c
gst/gstplugin.c

index 78a588f..761adb5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2003-12-15  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+       * gst/gst.c: (init_popt_callback):
+       * gst/gstplugin.c: (_gst_plugin_fault_handler_restore),
+       (_gst_plugin_fault_handler_sighandler),
+       (_gst_plugin_fault_handler_setup), (gst_plugin_load_file):
+       Implemented fault handlers for catching SIGSEGV while loading
+        plug-ins
+
 2003-12-02  Thomas Vander Stichele <thomas at apestaart dot org>
 
         * fix documentation build using docbook2..., works on fc1 and rh9
index 840a8a1..1e83dbc 100644 (file)
--- a/gst/gst.c
+++ b/gst/gst.c
@@ -55,6 +55,9 @@ static gboolean gst_initialized = FALSE;
 static gboolean _gst_initialization_failure = FALSE;
 extern gint _gst_trace_on;
 
+/* set to TRUE when segfaults need to be left as is */
+gboolean _gst_enable_segfault = FALSE;
+
 extern GThreadFunctions gst_thread_dummy_functions;
 
 
@@ -96,6 +99,7 @@ enum {
   ARG_PLUGIN_SPEW,
   ARG_PLUGIN_PATH,
   ARG_PLUGIN_LOAD,
+  ARG_SEGFAULT_ENABLE,
   ARG_SCHEDULER,
   ARG_REGISTRY
 };
@@ -122,6 +126,7 @@ static const struct poptOption gstreamer_options[] = {
   {"gst-plugin-spew",    NUL, POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   NULL, ARG_PLUGIN_SPEW,    N_("enable verbose plugin loading diagnostics"), NULL},
   {"gst-plugin-path",    NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_PATH,    N_("'" G_SEARCHPATH_SEPARATOR_S "'--separated path list for loading plugins"), "PATHS"},
   {"gst-plugin-load",    NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_PLUGIN_LOAD,    N_("comma-separated list of plugins to preload in addition to the list stored in env variable GST_PLUGIN_PATH"), "PLUGINS"},
+  {"gst-enable-segfault",NUL, POPT_ARG_NONE|POPT_ARGFLAG_STRIP,   NULL, ARG_SEGFAULT_ENABLE,N_("enable receiving of segmentation faults during plugin loading"), NULL},
   {"gst-scheduler",      NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_SCHEDULER,      N_("scheduler to use ('"GST_SCHEDULER_DEFAULT_NAME"' is the default)"), "SCHEDULER"},
   {"gst-registry",       NUL, POPT_ARG_STRING|POPT_ARGFLAG_STRIP, NULL, ARG_REGISTRY,       N_("registry to use") , "REGISTRY"},
   POPT_TABLEEND
@@ -700,6 +705,9 @@ init_popt_callback (poptContext context, enum poptCallbackReason reason,
     case ARG_PLUGIN_LOAD:
       split_and_iterate (arg, ",", prepare_for_load_plugin_func, NULL);
       break;
+    case ARG_SEGFAULT_ENABLE:
+      _gst_enable_segfault = TRUE;
+      break;
     case ARG_SCHEDULER:
       gst_scheduler_factory_set_default_name (arg);
       break;
index 97aeba0..622e8a5 100644 (file)
@@ -24,6 +24,7 @@
 #include <sys/stat.h>
 #include <dirent.h>
 #include <unistd.h>
+#include <signal.h>
 
 #include "gst_private.h"
 
 static GModule *main_module = NULL;
 static GList *_gst_plugin_static = NULL;
 
+/* static variables for segfault handling of plugin loading */
+static char *_gst_plugin_fault_handler_filename = NULL;
+extern gboolean *_gst_enable_segfault; /* see gst.c */
+static gboolean *_gst_plugin_fault_handler_is_setup = FALSE;
+
 /* list of valid licenses.
  * One of these must be specified or the plugin won't be loaded 
  * Contact gstreamer-devel@lists.sourceforge.net if your license should be 
@@ -195,13 +201,78 @@ gst_plugin_register_func (GstPlugin *plugin, GModule *module, GstPluginDesc *des
 }
 
 /**
+ * _gst_plugin_fault_handler_restore:
+ * segfault handler restorer
+ */
+static void
+_gst_plugin_fault_handler_restore (void)
+{
+  struct sigaction action;
+
+  memset (&action, 0, sizeof (action));
+  action.sa_handler = SIG_DFL;
+
+  sigaction (SIGSEGV, &action, NULL);
+}
+
+/**
+ * _gst_plugin_fault_handler_sighandler:
+ * segfault handler implementation
+ */
+static void
+_gst_plugin_fault_handler_sighandler (int signum)
+{
+  /* We need to restore the fault handler or we'll keep getting it */
+  _gst_plugin_fault_handler_restore ();
+
+  switch (signum)
+  {
+    case SIGSEGV:
+      g_print ("\nERROR:");
+      g_print ("Caught a segmentation fault while loading plugin file:\n");
+      g_print ("%s\n\n", _gst_plugin_fault_handler_filename);
+      g_print ("Please either:\n");
+      g_print ("- remove it and restart.\n");
+      g_print ("- run with --gst-enable-segfault and debug.\n");
+      exit (-1);
+      break;
+    default:
+      g_print ("Caught unhandled signal on plugin loading\n");
+      break;
+  }
+}
+
+/**
+ * _gst_plugin_fault_handler_setup:
+ * sets up the segfault handler
+ */
+static void
+_gst_plugin_fault_handler_setup (void)
+{
+  struct sigaction action;
+
+  /* if asked to leave segfaults alone, just return */
+  if (_gst_enable_segfault) return;
+
+  if (_gst_plugin_fault_handler_is_setup) return;
+
+  memset (&action, 0, sizeof (action));
+  action.sa_handler = _gst_plugin_fault_handler_sighandler;
+
+  sigaction (SIGSEGV, &action, NULL);
+}
+
+static void
+_gst_plugin_fault_handler_setup ();
+
+/**
  * gst_plugin_load_file:
  * @plugin: The plugin to load
  * @error: Pointer to a NULL-valued GError.
  *
  * Load the given plugin.
  *
- * Returns: a new GstPlugin or NULL, if an error occured
+ * Returns: a new GstPlugin or NULL, if an error occurred.
  */
 GstPlugin *
 gst_plugin_load_file (const gchar *filename, GError **error)
@@ -229,8 +300,8 @@ gst_plugin_load_file (const gchar *filename, GError **error)
                  GST_PLUGIN_ERROR,
                  GST_PLUGIN_ERROR_MODULE,
                  "Problem opening file %s\n",
-                 filename); 
-    return FALSE;
+                 filename);
+    return NULL;
   }
 
   module = g_module_open (filename, G_MODULE_BIND_LAZY);
@@ -278,10 +349,19 @@ gst_plugin_load_file (const gchar *filename, GError **error)
                      desc->name);
       }
 
+      /* this is where we load the actual .so, so let's trap SIGSEGV */
+      _gst_plugin_fault_handler_setup ();
+      _gst_plugin_fault_handler_filename = plugin->filename;
+
       if (gst_plugin_register_func (plugin, module, desc)) {
+        /* remove signal handler */
+        _gst_plugin_fault_handler_restore ();
+        _gst_plugin_fault_handler_filename = NULL;
         GST_INFO ("plugin \"%s\" loaded", plugin->filename);
         return plugin;
       } else {
+        /* remove signal handler */
+        _gst_plugin_fault_handler_restore ();
         GST_DEBUG ("gst_plugin_register_func failed for plugin \"%s\"", filename);
        /* plugin == NULL */
         g_set_error (error,