mirror of https://github.com/python/cpython
Bug #742342: make Python stop segfaulting on infinitely-recursive reload()s. Fixed by patch #922167.
Will backport.
This commit is contained in:
parent
f567ca3e1a
commit
276887b16d
|
@ -21,6 +21,7 @@ typedef struct _is {
|
|||
PyObject *modules;
|
||||
PyObject *sysdict;
|
||||
PyObject *builtins;
|
||||
PyObject *modules_reloading;
|
||||
|
||||
PyObject *codec_search_path;
|
||||
PyObject *codec_search_cache;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# For testing http://python.org/sf/742342, which reports that Python
|
||||
# segfaults (infinite recursion in C) in the presence of infinite
|
||||
# reload()ing. This module is imported by test_import.py:test_infinite_reload
|
||||
# to make sure this doesn't happen any more.
|
||||
|
||||
import infinite_reload
|
||||
reload(infinite_reload)
|
|
@ -193,6 +193,16 @@ class ImportTest(unittest.TestCase):
|
|||
if TESTFN in sys.modules:
|
||||
del sys.modules[TESTFN]
|
||||
|
||||
def test_infinite_reload(self):
|
||||
# Bug #742342 reports that Python segfaults (infinite recursion in C)
|
||||
# when faced with self-recursive reload()ing.
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
try:
|
||||
import infinite_reload
|
||||
finally:
|
||||
sys.path.pop(0)
|
||||
|
||||
def test_import_name_binding(self):
|
||||
# import x.y.z binds x in the current namespace
|
||||
import test as x
|
||||
|
|
|
@ -19,6 +19,9 @@ Core and builtins
|
|||
its argument, if it exists. If not, it will work like before. This allows
|
||||
customizing the output of dir() in the presence of a __getattr__().
|
||||
|
||||
- Patch #922167: Python no longer segfaults when faced with infinitely
|
||||
self-recursive reload() calls (as reported by bug #742342).
|
||||
|
||||
- Patch #1675981: remove unreachable code from ``type.__new__()`` method.
|
||||
|
||||
- Patch #1491866: change the complex() constructor to allow parthensized
|
||||
|
|
|
@ -340,6 +340,25 @@ imp_release_lock(PyObject *self, PyObject *noargs)
|
|||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyImport_GetModulesReloading(void)
|
||||
{
|
||||
PyInterpreterState *interp = PyThreadState_Get()->interp;
|
||||
if (interp->modules_reloading == NULL)
|
||||
Py_FatalError("PyImport_GetModuleDict: no modules_reloading dictionary!");
|
||||
return interp->modules_reloading;
|
||||
}
|
||||
|
||||
static void
|
||||
imp_modules_reloading_clear (void)
|
||||
{
|
||||
PyInterpreterState *interp = PyThreadState_Get()->interp;
|
||||
if (interp->modules_reloading == NULL)
|
||||
return;
|
||||
PyDict_Clear(interp->modules_reloading);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Helper for sys */
|
||||
|
||||
PyObject *
|
||||
|
@ -499,6 +518,7 @@ PyImport_Cleanup(void)
|
|||
PyDict_Clear(modules);
|
||||
interp->modules = NULL;
|
||||
Py_DECREF(modules);
|
||||
Py_CLEAR(interp->modules_reloading);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2401,8 +2421,9 @@ import_submodule(PyObject *mod, char *subname, char *fullname)
|
|||
PyObject *
|
||||
PyImport_ReloadModule(PyObject *m)
|
||||
{
|
||||
PyObject *modules_reloading = PyImport_GetModulesReloading();
|
||||
PyObject *modules = PyImport_GetModuleDict();
|
||||
PyObject *path = NULL, *loader = NULL;
|
||||
PyObject *path = NULL, *loader = NULL, *existing_m = NULL;
|
||||
char *name, *subname;
|
||||
char buf[MAXPATHLEN+1];
|
||||
struct filedescr *fdp;
|
||||
|
@ -2423,20 +2444,30 @@ PyImport_ReloadModule(PyObject *m)
|
|||
name);
|
||||
return NULL;
|
||||
}
|
||||
if ((existing_m = PyDict_GetItemString(modules_reloading, name)) != NULL) {
|
||||
/* Due to a recursive reload, this module is already being reloaded. */
|
||||
Py_INCREF(existing_m);
|
||||
return existing_m;
|
||||
}
|
||||
PyDict_SetItemString(modules_reloading, name, m);
|
||||
|
||||
subname = strrchr(name, '.');
|
||||
if (subname == NULL)
|
||||
subname = name;
|
||||
else {
|
||||
PyObject *parentname, *parent;
|
||||
parentname = PyString_FromStringAndSize(name, (subname-name));
|
||||
if (parentname == NULL)
|
||||
if (parentname == NULL) {
|
||||
imp_modules_reloading_clear();
|
||||
return NULL;
|
||||
}
|
||||
parent = PyDict_GetItem(modules, parentname);
|
||||
if (parent == NULL) {
|
||||
PyErr_Format(PyExc_ImportError,
|
||||
"reload(): parent %.200s not in sys.modules",
|
||||
PyString_AS_STRING(parentname));
|
||||
Py_DECREF(parentname);
|
||||
imp_modules_reloading_clear();
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(parentname);
|
||||
|
@ -2451,6 +2482,7 @@ PyImport_ReloadModule(PyObject *m)
|
|||
|
||||
if (fdp == NULL) {
|
||||
Py_XDECREF(loader);
|
||||
imp_modules_reloading_clear();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2467,6 +2499,7 @@ PyImport_ReloadModule(PyObject *m)
|
|||
*/
|
||||
PyDict_SetItemString(modules, name, m);
|
||||
}
|
||||
imp_modules_reloading_clear ();
|
||||
return newm;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ PyInterpreterState_New(void)
|
|||
Py_FatalError("Can't initialize threads for interpreter");
|
||||
#endif
|
||||
interp->modules = NULL;
|
||||
interp->modules_reloading = NULL;
|
||||
interp->sysdict = NULL;
|
||||
interp->builtins = NULL;
|
||||
interp->tstate_head = NULL;
|
||||
|
@ -107,6 +108,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
|
|||
Py_CLEAR(interp->codec_search_cache);
|
||||
Py_CLEAR(interp->codec_error_registry);
|
||||
Py_CLEAR(interp->modules);
|
||||
Py_CLEAR(interp->modules_reloading);
|
||||
Py_CLEAR(interp->sysdict);
|
||||
Py_CLEAR(interp->builtins);
|
||||
}
|
||||
|
|
|
@ -194,6 +194,9 @@ Py_InitializeEx(int install_sigs)
|
|||
interp->modules = PyDict_New();
|
||||
if (interp->modules == NULL)
|
||||
Py_FatalError("Py_Initialize: can't make modules dictionary");
|
||||
interp->modules_reloading = PyDict_New();
|
||||
if (interp->modules_reloading == NULL)
|
||||
Py_FatalError("Py_Initialize: can't make modules_reloading dictionary");
|
||||
|
||||
#ifdef Py_USING_UNICODE
|
||||
/* Init Unicode implementation; relies on the codec registry */
|
||||
|
@ -531,6 +534,7 @@ Py_NewInterpreter(void)
|
|||
/* XXX The following is lax in error checking */
|
||||
|
||||
interp->modules = PyDict_New();
|
||||
interp->modules_reloading = PyDict_New();
|
||||
|
||||
bimod = _PyImport_FindExtension("__builtin__", "__builtin__");
|
||||
if (bimod != NULL) {
|
||||
|
|
Loading…
Reference in New Issue