[Python-checkins] r54291 - in python/trunk: Include/pystate.h Lib/test/infinite_reload.py Lib/test/test_import.py Misc/NEWS Python/import.c Python/pystate.c Python/pythonrun.c

collin.winter python-checkins at python.org
Mon Mar 12 17:11:40 CET 2007


Author: collin.winter
Date: Mon Mar 12 17:11:39 2007
New Revision: 54291

Added:
   python/trunk/Lib/test/infinite_reload.py   (contents, props changed)
Modified:
   python/trunk/Include/pystate.h
   python/trunk/Lib/test/test_import.py
   python/trunk/Misc/NEWS
   python/trunk/Python/import.c
   python/trunk/Python/pystate.c
   python/trunk/Python/pythonrun.c
Log:
Bug #742342: make Python stop segfaulting on infinitely-recursive reload()s. Fixed by patch #922167.
Will backport.


Modified: python/trunk/Include/pystate.h
==============================================================================
--- python/trunk/Include/pystate.h	(original)
+++ python/trunk/Include/pystate.h	Mon Mar 12 17:11:39 2007
@@ -21,6 +21,7 @@
     PyObject *modules;
     PyObject *sysdict;
     PyObject *builtins;
+    PyObject *modules_reloading;
 
     PyObject *codec_search_path;
     PyObject *codec_search_cache;

Added: python/trunk/Lib/test/infinite_reload.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/test/infinite_reload.py	Mon Mar 12 17:11:39 2007
@@ -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)

Modified: python/trunk/Lib/test/test_import.py
==============================================================================
--- python/trunk/Lib/test/test_import.py	(original)
+++ python/trunk/Lib/test/test_import.py	Mon Mar 12 17:11:39 2007
@@ -192,6 +192,16 @@
             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

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Mon Mar 12 17:11:39 2007
@@ -19,6 +19,9 @@
   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

Modified: python/trunk/Python/import.c
==============================================================================
--- python/trunk/Python/import.c	(original)
+++ python/trunk/Python/import.c	Mon Mar 12 17:11:39 2007
@@ -340,6 +340,25 @@
 	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 @@
 	PyDict_Clear(modules);
 	interp->modules = NULL;
 	Py_DECREF(modules);
+	Py_CLEAR(interp->modules_reloading);
 }
 
 
@@ -2401,8 +2421,9 @@
 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 @@
 			     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 @@
 
 	if (fdp == NULL) {
 		Py_XDECREF(loader);
+		imp_modules_reloading_clear();
 		return NULL;
 	}
 
@@ -2467,6 +2499,7 @@
 		 */
 		PyDict_SetItemString(modules, name, m);
 	}
+	imp_modules_reloading_clear ();
 	return newm;
 }
 

Modified: python/trunk/Python/pystate.c
==============================================================================
--- python/trunk/Python/pystate.c	(original)
+++ python/trunk/Python/pystate.c	Mon Mar 12 17:11:39 2007
@@ -68,6 +68,7 @@
 			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 @@
 	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);
 }

Modified: python/trunk/Python/pythonrun.c
==============================================================================
--- python/trunk/Python/pythonrun.c	(original)
+++ python/trunk/Python/pythonrun.c	Mon Mar 12 17:11:39 2007
@@ -194,6 +194,9 @@
 	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 @@
 	/* 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) {


More information about the Python-checkins mailing list