From bcda667d3722f6d07ddd5e0101c25ca08b2d9a81 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Sep 2023 12:23:41 +1000 Subject: [PATCH] Fix crash executing a script when sys.modules doesn't contain __main__ While in practice sys.modules has __main__ module, the purpose of PyC_MainModule_Backup/Restore is to temporarily override __main__. Running code outside of the text editor (callbacks for timers for e.g.) could remove the __main__ module which would then crash when running a script from the text editor. --- source/blender/python/generic/py_capi_utils.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/source/blender/python/generic/py_capi_utils.cc b/source/blender/python/generic/py_capi_utils.cc index 1c53218a8cd..951aa62e491 100644 --- a/source/blender/python/generic/py_capi_utils.cc +++ b/source/blender/python/generic/py_capi_utils.cc @@ -1162,15 +1162,25 @@ bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]) void PyC_MainModule_Backup(PyObject **r_main_mod) { PyObject *modules = PyImport_GetModuleDict(); - *r_main_mod = PyDict_GetItemString(modules, "__main__"); - Py_XINCREF(*r_main_mod); /* don't free */ + PyObject *main_mod = PyDict_GetItemString(modules, "__main__"); + if (main_mod) { + /* Ensure the backed up module is kept until it's ownership */ + /* is transferred back to `sys.modules`. */ + Py_INCREF(main_mod); + } + *r_main_mod = main_mod; } void PyC_MainModule_Restore(PyObject *main_mod) { PyObject *modules = PyImport_GetModuleDict(); - PyDict_SetItemString(modules, "__main__", main_mod); - Py_XDECREF(main_mod); + if (main_mod) { + PyDict_SetItemString(modules, "__main__", main_mod); + Py_DECREF(main_mod); + } + else { + PyDict_DelItemString(modules, "__main__"); + } } bool PyC_IsInterpreterActive()