diff options
| author | Cyrille Bagard <nocbos@gmail.com> | 2025-01-13 07:34:49 (GMT) | 
|---|---|---|
| committer | Cyrille Bagard <nocbos@gmail.com> | 2025-01-13 07:34:49 (GMT) | 
| commit | 59ab0336eaab192ca2f02b67d143a1ba4d1aac2b (patch) | |
| tree | 824215b03d19bd8a188cc480b376d2ff882773eb /plugins | |
| parent | 71367e25e95b90b34891ec88083a52e0e0f60f13 (diff) | |
Handle load errors due to buggy Python plugins.
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/pychrysalide/bindings.c | 120 | ||||
| -rw-r--r-- | plugins/pychrysalide/bindings.h | 5 | ||||
| -rw-r--r-- | plugins/pychrysalide/core.c | 148 | 
3 files changed, 123 insertions, 150 deletions
| diff --git a/plugins/pychrysalide/bindings.c b/plugins/pychrysalide/bindings.c index 295667f..f715a8e 100644 --- a/plugins/pychrysalide/bindings.c +++ b/plugins/pychrysalide/bindings.c @@ -34,6 +34,7 @@  #include <config.h>  #include <common/cpp.h> +#include <common/extstr.h>  #include <plugins/pglist.h> // REMME ?  #include <plugins/self.h> // REMME ? @@ -929,13 +930,130 @@ PyObject *init_python_pychrysalide_module(const pyinit_details_t *details)   exit:      if (result == NULL && !details->standalone) -        /*log_pychrysalide_exception("Loading failed")*/; +        log_pychrysalide_exception("Python bindings loading failed");      return result;  } +/****************************************************************************** +*                                                                             * +*  Paramètres  : prefix = message d'introduction à faire apparaître à l'écran.* +*                                                                             * +*  Description : Présente dans le journal une exception survenue.             * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void log_pychrysalide_exception(const char *prefix, ...) +{ +    va_list ap;                             /* Compléments argumentaires   */ +    char *msg;                              /* Message complet à imprimer  */ +    PyObject *err_type;                     /* Type d'erreur Python        */ +    PyObject *err_value;                    /* Instance Python d'erreur    */ +    PyObject *err_traceback;                /* Trace Python associée       */ +    PyObject *err_string;                   /* Description Python d'erreur */ +    const char *err_msg;                    /* Représentation humaine      */ + +    assert(PyGILState_Check() == 1); + +    if (PyErr_Occurred()) +    { +        /* Base de la communication */ + +        va_start(ap, prefix); + +        vasprintf(&msg, prefix, ap); + +        va_end(ap); + +        /* Détails complémentaires */ + +        PyErr_Fetch(&err_type, &err_value, &err_traceback); + +        PyErr_NormalizeException(&err_type, &err_value, &err_traceback); + +        if (err_traceback == NULL) +        { +            err_traceback = Py_None; +            Py_INCREF(err_traceback); +        } + +        PyException_SetTraceback(err_value, err_traceback); + +        if (err_value == NULL) +            msg = stradd(msg, _(": no extra information is provided...")); + +        else +        { +            err_string = PyObject_Str(err_value); +            err_msg = PyUnicode_AsUTF8(err_string); + +            msg = stradd(msg, ": "); +            msg = stradd(msg, err_msg); + +            Py_DECREF(err_string); + +        } + +        /** +         * Bien que la documentation précise que la fonction PyErr_Fetch() +         * transfère la propritété des éléments retournés, la pratique +         * montre que le programme plante à la terminaison en cas d'exception. +         * +         * C'est par exemple le cas quand un greffon Python ne peut se lancer +         * correctement ; l'exception est alors levée à partir de la fonction +         * create_python_plugin() et le plantage intervient en sortie d'exécution, +         * au moment de la libération de l'extension Python : +         * +         *    ==14939== Jump to the invalid address stated on the next line +         *    ==14939==    at 0x1A8FCBC9: ??? +         *    ==14939==    by 0x53DCDB2: g_object_unref (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.5800.3) +         *    ==14939==    by 0x610F834: on_plugin_ref_toggle (pglist.c:370) +         *    ==14939==    by 0x610F31A: exit_all_plugins (pglist.c:153) +         *    ==14939==    by 0x10AD19: main (main.c:440) +         *    ==14939==  Address 0x1a8fcbc9 is not stack'd, malloc'd or (recently) free'd +         * +         * Curieusement, un appel à PyErr_PrintEx(1) corrige l'effet, alors qu'un +         * appel à PyErr_PrintEx(0) ne change rien. +         * +         * La seule différence de l'instruction set_sys_last_vars réside en quelques +         * lignes dans le code de l'interpréteur Python : +         * +         *    if (set_sys_last_vars) { +         *        _PySys_SetObjectId(&PyId_last_type, exception); +         *        _PySys_SetObjectId(&PyId_last_value, v); +         *        _PySys_SetObjectId(&PyId_last_traceback, tb); +         *    } +         * +         * L'explication n'est pas encore déterminé : bogue dans Chrysalide ou dans Python ? +         * L'ajout des éléments dans le dictionnaire du module sys ajoute une référence +         * à ces éléments. +         * +         * On reproduit ici le comportement du code correcteur avec PySys_SetObject(). +         */ + +        PySys_SetObject("last_type", err_type); +        PySys_SetObject("last_value", err_value); +        PySys_SetObject("last_traceback", err_traceback); + +        Py_XDECREF(err_traceback); +        Py_XDECREF(err_value); +        Py_XDECREF(err_type); + +        log_plugin_simple_message(LMT_EXT_ERROR, msg); + +        free(msg); + +    } + +} + +  /* ---------------------------------------------------------------------------------- */  /*                          FONCTIONS GLOBALES DE CHRYSALIDE                          */ diff --git a/plugins/pychrysalide/bindings.h b/plugins/pychrysalide/bindings.h index 1c63956..e9ee421 100644 --- a/plugins/pychrysalide/bindings.h +++ b/plugins/pychrysalide/bindings.h @@ -48,16 +48,15 @@ typedef struct _pyinit_details_t  {      bool standalone;                        /* Chargement depuis Python ?  */ -      bool (* populate_extra) (void);         /* Ajout de types ?            */ -  } pyinit_details_t;  /* Implémente le point d'entrée pour l'initialisation de Python. */  PyObject *init_python_pychrysalide_module(const pyinit_details_t *); - +/* Présente dans le journal une exception survenue. */ +void log_pychrysalide_exception(const char *, ...); diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c index e815e25..3c551c7 100644 --- a/plugins/pychrysalide/core.c +++ b/plugins/pychrysalide/core.c @@ -368,146 +368,6 @@ G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *pl -/****************************************************************************** -*                                                                             * -*  Paramètres  : prefix = message d'introduction à faire apparaître à l'écran.* -*                                                                             * -*  Description : Présente dans le journal une exception survenue.             * -*                                                                             * -*  Retour      : -                                                            * -*                                                                             * -*  Remarques   : -                                                            * -*                                                                             * -******************************************************************************/ - -void log_pychrysalide_exception(const char *prefix, ...) -{ -    va_list ap;                             /* Compléments argumentaires   */ -    char *msg;                              /* Message complet à imprimer  */ -    PyObject *err_type;                     /* Type d'erreur Python        */ -    PyObject *err_value;                    /* Instance Python d'erreur    */ -    PyObject *err_traceback;                /* Trace Python associée       */ -    PyObject *err_string;                   /* Description Python d'erreur */ -    const char *err_msg;                    /* Représentation humaine      */ - -    assert(PyGILState_Check() == 1); - -    if (PyErr_Occurred()) -    { -        /* Base de la communication */ - -        va_start(ap, prefix); - -        vasprintf(&msg, prefix, ap); - -        va_end(ap); - -        /* Détails complémentaires */ - -        PyErr_Fetch(&err_type, &err_value, &err_traceback); - -        PyErr_NormalizeException(&err_type, &err_value, &err_traceback); - -        if (err_traceback == NULL) -        { -            err_traceback = Py_None; -            Py_INCREF(err_traceback); -        } - -        PyException_SetTraceback(err_value, err_traceback); - -        if (err_value == NULL) -            msg = stradd(msg, _(": no extra information is provided...")); - -        else -        { -            err_string = PyObject_Str(err_value); -            err_msg = PyUnicode_AsUTF8(err_string); - -            msg = stradd(msg, ": "); -            msg = stradd(msg, err_msg); - -            Py_DECREF(err_string); - -        } - -        /** -         * Bien que la documentation précise que la fonction PyErr_Fetch() -         * transfère la propritété des éléments retournés, la pratique -         * montre que le programme plante à la terminaison en cas d'exception. -         * -         * C'est par exemple le cas quand un greffon Python ne peut se lancer -         * correctement ; l'exception est alors levée à partir de la fonction -         * create_python_plugin() et le plantage intervient en sortie d'exécution, -         * au moment de la libération de l'extension Python : -         * -         *    ==14939== Jump to the invalid address stated on the next line -         *    ==14939==    at 0x1A8FCBC9: ??? -         *    ==14939==    by 0x53DCDB2: g_object_unref (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.5800.3) -         *    ==14939==    by 0x610F834: on_plugin_ref_toggle (pglist.c:370) -         *    ==14939==    by 0x610F31A: exit_all_plugins (pglist.c:153) -         *    ==14939==    by 0x10AD19: main (main.c:440) -         *    ==14939==  Address 0x1a8fcbc9 is not stack'd, malloc'd or (recently) free'd -         * -         * Curieusement, un appel à PyErr_PrintEx(1) corrige l'effet, alors qu'un -         * appel à PyErr_PrintEx(0) ne change rien. -         * -         * La seule différence de l'instruction set_sys_last_vars réside en quelques -         * lignes dans le code de l'interpréteur Python : -         * -         *    if (set_sys_last_vars) { -         *        _PySys_SetObjectId(&PyId_last_type, exception); -         *        _PySys_SetObjectId(&PyId_last_value, v); -         *        _PySys_SetObjectId(&PyId_last_traceback, tb); -         *    } -         * -         * L'explication n'est pas encore déterminé : bogue dans Chrysalide ou dans Python ? -         * L'ajout des éléments dans le dictionnaire du module sys ajoute une référence -         * à ces éléments. -         * -         * On reproduit ici le comportement du code correcteur avec PySys_SetObject(). -         */ - -        PySys_SetObject("last_type", err_type); -        PySys_SetObject("last_value", err_value); -        PySys_SetObject("last_traceback", err_traceback); - -        Py_XDECREF(err_traceback); -        Py_XDECREF(err_value); -        Py_XDECREF(err_type); - -        log_plugin_simple_message(LMT_ERROR, msg); - -        free(msg); - -    } - -} - - - - - - - - - - - - - - - - - - - - - - - - -  /* ---------------------------------------------------------------------------------- */  /*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */  /* ---------------------------------------------------------------------------------- */ @@ -685,8 +545,6 @@ static GPluginModule *create_python_plugin(const char *modname, const char *file      result = G_PLUGIN_MODULE(pygobject_get(instance)); -    ///result->filename = strdup(filename); -      /**       * L'instance Python et l'objet GLib résultant sont un même PyGObject.       * @@ -696,13 +554,11 @@ static GPluginModule *create_python_plugin(const char *modname, const char *file      Py_DECREF(module); -    printf(" -> REF: %p %u\n", result, G_OBJECT(result)->ref_count); -      return result;   no_instance: -    //log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance")); +    log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance"));   no_class: @@ -714,7 +570,7 @@ static GPluginModule *create_python_plugin(const char *modname, const char *file      Py_XDECREF(module); -    //log_pychrysalide_exception(_("An error occured when importing '%s'"), modname); +    log_pychrysalide_exception(_("An error occured when importing '%s'"), modname);   bad_exit: | 
