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/pychrysalide/bindings.c | |
parent | 71367e25e95b90b34891ec88083a52e0e0f60f13 (diff) |
Handle load errors due to buggy Python plugins.
Diffstat (limited to 'plugins/pychrysalide/bindings.c')
-rw-r--r-- | plugins/pychrysalide/bindings.c | 120 |
1 files changed, 119 insertions, 1 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 */ |