Commit 276887b1 authored by Collin Winter's avatar Collin Winter

Bug #742342: make Python stop segfaulting on infinitely-recursive reload()s....

Bug #742342: make Python stop segfaulting on infinitely-recursive reload()s. Fixed by patch #922167.
Will backport.
parent f567ca3e
...@@ -21,6 +21,7 @@ typedef struct _is { ...@@ -21,6 +21,7 @@ typedef struct _is {
PyObject *modules; PyObject *modules;
PyObject *sysdict; PyObject *sysdict;
PyObject *builtins; PyObject *builtins;
PyObject *modules_reloading;
PyObject *codec_search_path; PyObject *codec_search_path;
PyObject *codec_search_cache; PyObject *codec_search_cache;
......
# 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)
...@@ -192,6 +192,16 @@ class ImportTest(unittest.TestCase): ...@@ -192,6 +192,16 @@ class ImportTest(unittest.TestCase):
remove_files(TESTFN) remove_files(TESTFN)
if TESTFN in sys.modules: if TESTFN in sys.modules:
del sys.modules[TESTFN] 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): def test_import_name_binding(self):
# import x.y.z binds x in the current namespace # import x.y.z binds x in the current namespace
......
...@@ -19,6 +19,9 @@ Core and builtins ...@@ -19,6 +19,9 @@ Core and builtins
its argument, if it exists. If not, it will work like before. This allows 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__(). 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 #1675981: remove unreachable code from ``type.__new__()`` method.
- Patch #1491866: change the complex() constructor to allow parthensized - Patch #1491866: change the complex() constructor to allow parthensized
......
...@@ -340,6 +340,25 @@ imp_release_lock(PyObject *self, PyObject *noargs) ...@@ -340,6 +340,25 @@ imp_release_lock(PyObject *self, PyObject *noargs)
return Py_None; 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 */ /* Helper for sys */
PyObject * PyObject *
...@@ -499,6 +518,7 @@ PyImport_Cleanup(void) ...@@ -499,6 +518,7 @@ PyImport_Cleanup(void)
PyDict_Clear(modules); PyDict_Clear(modules);
interp->modules = NULL; interp->modules = NULL;
Py_DECREF(modules); Py_DECREF(modules);
Py_CLEAR(interp->modules_reloading);
} }
...@@ -2401,8 +2421,9 @@ import_submodule(PyObject *mod, char *subname, char *fullname) ...@@ -2401,8 +2421,9 @@ import_submodule(PyObject *mod, char *subname, char *fullname)
PyObject * PyObject *
PyImport_ReloadModule(PyObject *m) PyImport_ReloadModule(PyObject *m)
{ {
PyObject *modules_reloading = PyImport_GetModulesReloading();
PyObject *modules = PyImport_GetModuleDict(); PyObject *modules = PyImport_GetModuleDict();
PyObject *path = NULL, *loader = NULL; PyObject *path = NULL, *loader = NULL, *existing_m = NULL;
char *name, *subname; char *name, *subname;
char buf[MAXPATHLEN+1]; char buf[MAXPATHLEN+1];
struct filedescr *fdp; struct filedescr *fdp;
...@@ -2423,20 +2444,30 @@ PyImport_ReloadModule(PyObject *m) ...@@ -2423,20 +2444,30 @@ PyImport_ReloadModule(PyObject *m)
name); name);
return NULL; 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, '.'); subname = strrchr(name, '.');
if (subname == NULL) if (subname == NULL)
subname = name; subname = name;
else { else {
PyObject *parentname, *parent; PyObject *parentname, *parent;
parentname = PyString_FromStringAndSize(name, (subname-name)); parentname = PyString_FromStringAndSize(name, (subname-name));
if (parentname == NULL) if (parentname == NULL) {
imp_modules_reloading_clear();
return NULL; return NULL;
}
parent = PyDict_GetItem(modules, parentname); parent = PyDict_GetItem(modules, parentname);
if (parent == NULL) { if (parent == NULL) {
PyErr_Format(PyExc_ImportError, PyErr_Format(PyExc_ImportError,
"reload(): parent %.200s not in sys.modules", "reload(): parent %.200s not in sys.modules",
PyString_AS_STRING(parentname)); PyString_AS_STRING(parentname));
Py_DECREF(parentname); Py_DECREF(parentname);
imp_modules_reloading_clear();
return NULL; return NULL;
} }
Py_DECREF(parentname); Py_DECREF(parentname);
...@@ -2451,6 +2482,7 @@ PyImport_ReloadModule(PyObject *m) ...@@ -2451,6 +2482,7 @@ PyImport_ReloadModule(PyObject *m)
if (fdp == NULL) { if (fdp == NULL) {
Py_XDECREF(loader); Py_XDECREF(loader);
imp_modules_reloading_clear();
return NULL; return NULL;
} }
...@@ -2467,6 +2499,7 @@ PyImport_ReloadModule(PyObject *m) ...@@ -2467,6 +2499,7 @@ PyImport_ReloadModule(PyObject *m)
*/ */
PyDict_SetItemString(modules, name, m); PyDict_SetItemString(modules, name, m);
} }
imp_modules_reloading_clear ();
return newm; return newm;
} }
......
...@@ -68,6 +68,7 @@ PyInterpreterState_New(void) ...@@ -68,6 +68,7 @@ PyInterpreterState_New(void)
Py_FatalError("Can't initialize threads for interpreter"); Py_FatalError("Can't initialize threads for interpreter");
#endif #endif
interp->modules = NULL; interp->modules = NULL;
interp->modules_reloading = NULL;
interp->sysdict = NULL; interp->sysdict = NULL;
interp->builtins = NULL; interp->builtins = NULL;
interp->tstate_head = NULL; interp->tstate_head = NULL;
...@@ -107,6 +108,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp) ...@@ -107,6 +108,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
Py_CLEAR(interp->codec_search_cache); Py_CLEAR(interp->codec_search_cache);
Py_CLEAR(interp->codec_error_registry); Py_CLEAR(interp->codec_error_registry);
Py_CLEAR(interp->modules); Py_CLEAR(interp->modules);
Py_CLEAR(interp->modules_reloading);
Py_CLEAR(interp->sysdict); Py_CLEAR(interp->sysdict);
Py_CLEAR(interp->builtins); Py_CLEAR(interp->builtins);
} }
......
...@@ -194,6 +194,9 @@ Py_InitializeEx(int install_sigs) ...@@ -194,6 +194,9 @@ Py_InitializeEx(int install_sigs)
interp->modules = PyDict_New(); interp->modules = PyDict_New();
if (interp->modules == NULL) if (interp->modules == NULL)
Py_FatalError("Py_Initialize: can't make modules dictionary"); 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 #ifdef Py_USING_UNICODE
/* Init Unicode implementation; relies on the codec registry */ /* Init Unicode implementation; relies on the codec registry */
...@@ -531,6 +534,7 @@ Py_NewInterpreter(void) ...@@ -531,6 +534,7 @@ Py_NewInterpreter(void)
/* XXX The following is lax in error checking */ /* XXX The following is lax in error checking */
interp->modules = PyDict_New(); interp->modules = PyDict_New();
interp->modules_reloading = PyDict_New();
bimod = _PyImport_FindExtension("__builtin__", "__builtin__"); bimod = _PyImport_FindExtension("__builtin__", "__builtin__");
if (bimod != NULL) { if (bimod != NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment