# HG changeset patch
# Node ID 906a89f95016
# Parent  0bc3ce384653
diff --git a/gplugin/gplugin-native-loader.c b/gplugin/gplugin-native-loader.c
--- a/gplugin/gplugin-native-loader.c
+++ b/gplugin/gplugin-native-loader.c
@@ -73,32 +73,6 @@
 	return symbol;
 }
 
-static GModule *
-gplugin_native_loader_open(
-	const gchar *filename,
-	GModuleFlags flags,
-	GError **error)
-{
-	GModule *module = NULL;
-
-	module = g_module_open(filename, flags);
-	if(module)
-		return module;
-
-	if(error) {
-		const gchar *msg = g_module_error();
-
-		*error = g_error_new(
-			GPLUGIN_DOMAIN,
-			0,
-			_("Failed to open plugin '%s': %s"),
-			filename,
-			(msg) ? msg : _("Unknown error"));
-	}
-
-	return NULL;
-}
-
 /******************************************************************************
  * GPluginLoaderInterface API
  *****************************************************************************/
@@ -127,31 +101,48 @@
 	GError **error)
 {
 	GPluginPluginInfo *info = NULL;
+	GError *local_error = NULL;
 
-	*module = gplugin_native_loader_open(filename, flags, error);
-	if(*module == NULL) {
-		return NULL;
-	} else if(error && *error) {
-		g_module_close(*module);
-		*module = NULL;
+	*module = g_module_open_full(filename, flags, &local_error);
+	if(local_error != NULL) {
+		if(*module != NULL) {
+			g_module_close(*module);
+			*module = NULL;
+		}
+
+		g_propagate_error(error, local_error);
+
 		return NULL;
 	}
 
 	*query = gplugin_native_loader_lookup_symbol(
 		*module,
 		GPLUGIN_QUERY_SYMBOL,
-		error);
-
-	if((*query == NULL) || (error && *error)) {
+		&local_error);
+	if(local_error != NULL) {
 		g_module_close(*module);
 		*module = NULL;
+
+		g_propagate_error(error, local_error);
+
 		return NULL;
 	}
 
-	info = ((GPluginNativePluginQueryFunc)(*query))(error);
-	if(error && *error) {
+	info = ((GPluginNativePluginQueryFunc)(*query))(&local_error);
+	if(local_error != NULL) {
+		/* We can't use g_propagate_error here, because local_error is pointing
+		 * to memory in the address space of the module we're about to close.
+		 * So instead, create a copy of it and free it before closing the
+		 * module.
+		 */
+		if(error != NULL && *error == NULL) {
+			*error = g_error_copy(local_error);
+		}
+		g_clear_error(&local_error);
+
 		g_module_close(*module);
 		*module = NULL;
+
 		return NULL;
 	}
 
@@ -169,6 +160,7 @@
 	GPluginNativePluginLoadFunc load = NULL;
 	GPluginNativePluginQueryFunc query = NULL;
 	GPluginNativePluginUnloadFunc unload = NULL;
+	GError *local_error = NULL;
 	GModule *module = NULL;
 
 	info = gplugin_native_loader_open_and_query(
@@ -176,12 +168,13 @@
 		&module,
 		G_MODULE_BIND_LOCAL,
 		&query,
-		error);
+		&local_error);
 
 	/* If the query returned an error, clear any info it may have set and return
 	 * NULL.
 	 */
-	if(error != NULL && *error != NULL) {
+	if(local_error != NULL) {
+		g_propagate_error(error, local_error);
 		g_clear_object(&info);
 
 		return NULL;
@@ -203,17 +196,23 @@
 	}
 
 	if(gplugin_plugin_info_get_bind_global(info)) {
+		/* Clear the info first, as closing the module with invalid the
+		 * memory that info is pointing to.
+		 */
+		g_clear_object(&info);
 		g_module_close(module);
-		g_object_unref(G_OBJECT(info));
 
 		info = gplugin_native_loader_open_and_query(
 			filename,
 			&module,
 			0,
 			&query,
-			error);
+			&local_error);
+
 		if(!GPLUGIN_IS_PLUGIN_INFO(info)) {
-			if(error && *error == NULL) {
+			if(local_error != NULL) {
+				g_propagate_error(error, local_error);
+			} else {
 				g_set_error_literal(
 					error,
 					GPLUGIN_DOMAIN,
@@ -227,11 +226,16 @@
 	}
 
 	/* now look for the load symbol */
-	load =
-		gplugin_native_loader_lookup_symbol(module, GPLUGIN_LOAD_SYMBOL, error);
-	if(error && *error) {
+	load = gplugin_native_loader_lookup_symbol(
+		module,
+		GPLUGIN_LOAD_SYMBOL,
+		&local_error);
+	if(local_error != NULL) {
+		g_clear_object(&info);
 		g_module_close(module);
-		g_object_unref(G_OBJECT(info));
+
+		g_propagate_error(error, local_error);
+
 		return NULL;
 	}
 
@@ -239,10 +243,13 @@
 	unload = gplugin_native_loader_lookup_symbol(
 		module,
 		GPLUGIN_UNLOAD_SYMBOL,
-		error);
-	if(error && *error) {
+		&local_error);
+	if(local_error != NULL) {
+		g_clear_object(&info);
 		g_module_close(module);
-		g_object_unref(G_OBJECT(info));
+
+		g_propagate_error(error, local_error);
+
 		return NULL;
 	}
 
@@ -260,7 +267,7 @@
 	/* clang-format on */
 
 	/* now that the plugin instance owns the info, remove our ref */
-	g_object_unref(G_OBJECT(info));
+	g_clear_object(&info);
 
 	if(!GPLUGIN_IS_NATIVE_PLUGIN(plugin)) {
 		g_module_close(module);
@@ -269,6 +276,7 @@
 			GPLUGIN_DOMAIN,
 			0,
 			_("failed to create plugin instance"));
+
 		return NULL;
 	}
 
@@ -282,15 +290,19 @@
 	GError **error)
 {
 	GPluginNativePluginLoadFunc func;
+	GError *local_error = NULL;
 
 	g_return_val_if_fail(plugin != NULL, FALSE);
 	g_return_val_if_fail(GPLUGIN_IS_NATIVE_PLUGIN(plugin), FALSE);
 
 	/* get and call the function */
 	g_object_get(G_OBJECT(plugin), "load-func", &func, NULL);
-	if(!func(plugin, error)) {
-		if(error && *error == NULL)
+	if(!func(plugin, &local_error)) {
+		if(local_error != NULL) {
+			g_propagate_error(error, local_error);
+		} else {
 			g_set_error_literal(error, GPLUGIN_DOMAIN, 0, _("unknown failure"));
+		}
 
 		return FALSE;
 	}
@@ -306,6 +318,7 @@
 	GError **error)
 {
 	GPluginNativePluginUnloadFunc func;
+	GError *local_error = NULL;
 
 	g_return_val_if_fail(plugin != NULL, FALSE);
 	g_return_val_if_fail(GPLUGIN_IS_NATIVE_PLUGIN(plugin), FALSE);
@@ -325,9 +338,12 @@
 	}
 
 	/* now call the function */
-	if(!func(plugin, shutdown, error)) {
-		if(error && *error == NULL)
+	if(!func(plugin, shutdown, &local_error)) {
+		if(local_error != NULL) {
+			g_propagate_error(error, local_error);
+		} else {
 			g_set_error_literal(error, GPLUGIN_DOMAIN, 0, _("unknown failure"));
+		}
 
 		return FALSE;
 	}
diff --git a/gplugin/tests/test-native-loader.c b/gplugin/tests/test-native-loader.c
--- a/gplugin/tests/test-native-loader.c
+++ b/gplugin/tests/test-native-loader.c
@@ -59,27 +59,24 @@
  * Test bad plugins
  *****************************************************************************/
 static void
-test_query_error_subprocess(void)
-{
-	GPluginManager *manager = gplugin_manager_get_default();
-	GPluginPlugin *plugin = NULL;
-
-	/* add the test directory to the plugin manager's search paths */
-	gplugin_manager_append_path(manager, TEST_BAD_DIR);
-
-	/* refresh the plugin manager */
-	gplugin_manager_refresh(manager);
-
-	/* find the query-error plugin */
-	plugin = gplugin_manager_find_plugin(manager, "gplugin/query-error");
-	g_assert_null(plugin);
-}
-
-static void
 test_query_error(void)
 {
-	g_test_trap_subprocess("/loaders/native/error/query/subprocess", 0, 0);
+	if(g_test_subprocess()) {
+		GPluginManager *manager = gplugin_manager_get_default();
+		GPluginPlugin *plugin = NULL;
+
+		/* add the test directory to the plugin manager's search paths */
+		gplugin_manager_append_path(manager, TEST_BAD_DIR);
 
+		/* refresh the plugin manager */
+		gplugin_manager_refresh(manager);
+
+		/* find the query-error plugin */
+		plugin = gplugin_manager_find_plugin(manager, "gplugin/query-error");
+		g_assert_null(plugin);
+	}
+
+	g_test_trap_subprocess(NULL, 0, 0);
 	g_test_trap_assert_stderr("*expected error*");
 }
 
@@ -102,9 +99,6 @@
 
 	/* bad plugin tests */
 	g_test_add_func("/loaders/native/error/query", test_query_error);
-	g_test_add_func(
-		"/loaders/native/error/query/subprocess",
-		test_query_error_subprocess);
 
 	return g_test_run();
 }
