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

Will backport.
This commit is contained in:
Collin Winter 2007-03-12 16:11:39 +00:00
parent f567ca3e1a
commit 276887b16d
7 changed files with 62 additions and 2 deletions

View File

@ -21,6 +21,7 @@ typedef struct _is {
PyObject *modules;
PyObject *sysdict;
PyObject *builtins;
PyObject *modules_reloading;
PyObject *codec_search_path;
PyObject *codec_search_cache;

View File

@ -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)

View File

@ -192,6 +192,16 @@ class ImportTest(unittest.TestCase):
remove_files(TESTFN)
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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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) {