]> granicus.if.org Git - python/commitdiff
Bug #742342: make Python stop segfaulting on infinitely-recursive reload()s. Fixed...
authorCollin Winter <collinw@gmail.com>
Mon, 12 Mar 2007 16:11:39 +0000 (16:11 +0000)
committerCollin Winter <collinw@gmail.com>
Mon, 12 Mar 2007 16:11:39 +0000 (16:11 +0000)
Will backport.

Include/pystate.h
Lib/test/infinite_reload.py [new file with mode: 0644]
Lib/test/test_import.py
Misc/NEWS
Python/import.c
Python/pystate.c
Python/pythonrun.c

index cf2969596310499f617c0a6abea1d69063635782..4919d99b6c76bca1664b3e48f7977c29397ef68d 100644 (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;
diff --git a/Lib/test/infinite_reload.py b/Lib/test/infinite_reload.py
new file mode 100644 (file)
index 0000000..bfbec91
--- /dev/null
@@ -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)
index a6db28129971829f6f59c3d1f979a48adde65e41..cc932a2ec2ae28f242a91b37316cb9731d7a70dd 100644 (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
index 67f417a2b4efbc5fa3d77de64f98e79c75084a53..0bd82c2debca581c40bdf4934151b044c483828a 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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
index db39cc4ee0a71304512d681529b963d20c8f9b86..d7f012ac1c31165f08a1bad73ac422b382c39aee 100644 (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;
 }
 
index cc25e3ed38e95edf45391ca37e4d03ee243892e3..086789d3553cc909cd70fe60a880c4611153300e 100644 (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);
 }
index 3a9e75e2373adf87f28f7edbc32ab8e059704c2c..3e5ecfe3f621c365175beed4eaa7513c1e22f308 100644 (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) {