From e790ebee8ad78e91fc61738c5c40062ed36b1d44 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 3 Jan 2021 16:12:38 +0100 Subject: Fixed a memory leak when a Python plugin fails to load. --- plugins/pychrysalide/core.c | 31 +++++++++++-------------------- plugins/pychrysalide/plugin.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c index a148654..7bc46e4 100644 --- a/plugins/pychrysalide/core.c +++ b/plugins/pychrysalide/core.c @@ -664,6 +664,7 @@ static void load_python_plugins(GPluginModule *plugin) struct dirent *entry; /* Elément trouvé */ char *modname; /* Nom du module pour Python */ char *filename; /* Chemin d'accès reconstruit */ + PyThreadState *tstate; /* Contexte d'environnement */ GPluginModule *pyplugin; /* Lien vers un grffon Python */ bool status; /* Bilan d'une opération */ GGenConfig *config; /* Configuration à charger */ @@ -743,8 +744,17 @@ static void load_python_plugins(GPluginModule *plugin) filename = stradd(filename, G_DIR_SEPARATOR_S); filename = stradd(filename, entry->d_name); + if (!_standalone) + { + tstate = get_pychrysalide_main_tstate(); + PyEval_RestoreThread(tstate); + } + pyplugin = g_python_plugin_new(modname, filename); + if (!_standalone) + PyEval_SaveThread(); + if (pyplugin == NULL) { g_plugin_module_log_variadic_message(plugin, LMT_ERROR, @@ -761,6 +771,7 @@ static void load_python_plugins(GPluginModule *plugin) { g_plugin_module_log_variadic_message(plugin, LMT_ERROR, _("Plugin '%s' failed to complete loading..."), filename); + g_object_unref(G_OBJECT(pyplugin)); goto done_with_plugin; } @@ -772,12 +783,6 @@ static void load_python_plugins(GPluginModule *plugin) _("Loaded the Python plugin found in the '%s' directory"), filename); - /** - * Comme le greffon n'est pas passé par la résolution des dépendances, - * on simule l'effet attendu. - */ - g_object_ref(G_OBJECT(plugin)); - _register_plugin(pyplugin); done_with_plugin: @@ -894,23 +899,9 @@ G_MODULE_EXPORT void chrysalide_plugin_exit(GPluginModule *plugin) G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, PluginAction action) { - PyThreadState *tstate; /* Contexte d'environnement */ - if (action == PGA_NATIVE_PLUGINS_LOADED) - { - if (!_standalone) - { - tstate = get_pychrysalide_main_tstate(); - PyEval_RestoreThread(tstate); - } - load_python_plugins(plugin); - if (!_standalone) - PyEval_SaveThread(); - - } - } diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c index aa91fb8..88b20de 100644 --- a/plugins/pychrysalide/plugin.c +++ b/plugins/pychrysalide/plugin.c @@ -34,6 +34,7 @@ #include #include +#include #include @@ -274,6 +275,7 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds) int ret; /* Bilan d'un appel */ GPluginModule *plugin; /* Greffon à manipuler */ plugin_interface *iface; /* Interface à constituer */ + GPluginModule *dependency; /* Module nécessaire */ PyObject *value; /* Valeur à présence imposée */ size_t i; /* Boucle de parcours */ PyObject *action; /* Identifiant d'une action */ @@ -353,10 +355,37 @@ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds) iface->container = false; + /** + * Comme le greffon n'est pas passé par la résolution des dépendances, + * orchestrée par la fonction g_plugin_module_resolve_dependencies(), + * on simule l'effet attendu en obtenant une référence par un appel à + * get_plugin_by_name(). + * + * L'incrémentation des références doit coller au plus près de + * l'inscription nominative du greffon : en cas de sortie impromptue + * (lorsqu'une erreur intervient pendant un chargement par exemple), + * l'état de l'ensemble est ainsi cohérent au moment du retrait du + * greffon fautif via la fonction g_plugin_module_dispose(). + */ + + lock_plugin_list_for_reading(); + dependency = get_plugin_by_name("PyChrysalide", NULL); + unlock_plugin_list_for_reading(); + + assert(dependency != NULL); + + if (dependency == NULL) + { + PyErr_SetString(PyExc_TypeError, _("The internal name of the Python plugin has changed!")); + return -1; + } + iface->required = malloc(sizeof(char *)); iface->required[0] = "PyChrysalide"; iface->required_count = 1; + /* Validation du reste de l'interface */ + value = PyObject_GetAttrString(self, "_actions"); if (value == NULL) @@ -1331,6 +1360,7 @@ static void g_python_plugin_init(GPythonPlugin *plugin) static void g_python_plugin_dispose(GPythonPlugin *plugin) { +#if 0 PyThreadState *tstate; /* Contexte d'environnement */ /** @@ -1361,6 +1391,7 @@ static void g_python_plugin_dispose(GPythonPlugin *plugin) if (tstate != NULL) PyEval_SaveThread(); +#endif G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); @@ -1392,7 +1423,7 @@ static void g_python_plugin_finalize(GPythonPlugin *plugin) if (final->version != NULL) free(final->version); if (final->url != NULL) free(final->url); - assert(final->required_count <= 1); + assert(final->required_count == 1); if (final->required != NULL) free(final->required); -- cgit v0.11.2-87-g4458