From a4f74f5eb439ad71ad7eb368790cd944161909c2 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Mon, 15 Dec 2003 12:44:35 +0000 Subject: [PATCH] implementing segfault handler for plugin loading Original commit message from CVS: implementing segfault handler for plugin loading --- ChangeLog | 9 ++++++ gst/gst.c | 8 +++++ gst/gstplugin.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 78a588f3a3..761adb5581 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2003-12-15 Thomas Vander Stichele + + * 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 * fix documentation build using docbook2..., works on fc1 and rh9 diff --git a/gst/gst.c b/gst/gst.c index 840a8a1b95..1e83dbc26d 100644 --- 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; diff --git a/gst/gstplugin.c b/gst/gstplugin.c index 97aeba0f56..622e8a5d1a 100644 --- a/gst/gstplugin.c +++ b/gst/gstplugin.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "gst_private.h" @@ -39,6 +40,11 @@ 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 @@ -194,6 +200,71 @@ gst_plugin_register_func (GstPlugin *plugin, GModule *module, GstPluginDesc *des return plugin; } +/** + * _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 @@ -201,7 +272,7 @@ gst_plugin_register_func (GstPlugin *plugin, GModule *module, GstPluginDesc *des * * 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,