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 *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;

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

View File

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

View File

@ -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)
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)
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)
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)
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)
*/ */
PyDict_SetItemString(modules, name, m); PyDict_SetItemString(modules, name, m);
} }
imp_modules_reloading_clear ();
return newm; return newm;
} }

View File

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

View File

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