From 8287aadb75f6bd0154996424819334cd3839707c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 11 Oct 2020 16:51:07 +0300 Subject: bpo-41993: Fix possible issues in remove_module() (GH-22631) * PyMapping_HasKey() is not safe because it silences all exceptions and can return incorrect result. * Informative exceptions from PyMapping_DelItem() are overridden with RuntimeError and the original exception raised before calling remove_module() is lost. * There is a race condition between PyMapping_HasKey() and PyMapping_DelItem(). --- .../2020-10-10-13-53-52.bpo-41993.YMzixQ.rst | 2 ++ Python/import.c | 23 ++++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst new file mode 100644 index 0000000..3669cf1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-10-13-53-52.bpo-41993.YMzixQ.rst @@ -0,0 +1,2 @@ +Fixed potential issues with removing not completely initialized module from +``sys.modules`` when import fails. diff --git a/Python/import.c b/Python/import.c index 5056884..26b80f3 100644 --- a/Python/import.c +++ b/Python/import.c @@ -902,7 +902,11 @@ PyImport_AddModule(const char *name) } -/* Remove name from sys.modules, if it's there. */ +/* Remove name from sys.modules, if it's there. + * Can be called with an exception raised. + * If fail to remove name a new exception will be chained with the old + * exception, otherwise the old exception is preserved. + */ static void remove_module(PyThreadState *tstate, PyObject *name) { @@ -910,18 +914,17 @@ remove_module(PyThreadState *tstate, PyObject *name) _PyErr_Fetch(tstate, &type, &value, &traceback); PyObject *modules = tstate->interp->modules; - if (!PyMapping_HasKey(modules, name)) { - goto out; + if (PyDict_CheckExact(modules)) { + PyObject *mod = _PyDict_Pop(modules, name, Py_None); + Py_XDECREF(mod); } - if (PyMapping_DelItem(modules, name) < 0) { - _PyErr_SetString(tstate, PyExc_RuntimeError, - "deleting key in sys.modules failed"); - _PyErr_ChainExceptions(type, value, traceback); - return; + else if (PyMapping_DelItem(modules, name) < 0) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + _PyErr_Clear(tstate); + } } -out: - _PyErr_Restore(tstate, type, value, traceback); + _PyErr_ChainExceptions(type, value, traceback); } -- cgit v0.12