summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrent Nelson <trent.nelson@snakebite.org>2008-03-19 06:45:48 (GMT)
committerTrent Nelson <trent.nelson@snakebite.org>2008-03-19 06:45:48 (GMT)
commit39e307e224bae1e1bb0e236aba5e76515d220eec (patch)
treeff516404a0ed4fbc01f91b96201aa18fb5eafcf8
parent8a5f8ca33b56db9af973d1f34a9b3df5271b56c0 (diff)
downloadcpython-39e307e224bae1e1bb0e236aba5e76515d220eec.zip
cpython-39e307e224bae1e1bb0e236aba5e76515d220eec.tar.gz
cpython-39e307e224bae1e1bb0e236aba5e76515d220eec.tar.bz2
Issue2297: Fix a stack overflow in Windows caused by -v and -vv. When python is invoked with -v or -vv under Windows, the process of importing the codec for sys.stderr causes a message to be written to stderr, which in turn causes the codec to be recursively imported. Sometimes the stack overflow exception is swallowed, other times it is not. The bug depends on the particular locale settings of the Windows machine.
Kudos to Douglas Greiman for reporting the issue and providing a patch and test case.
-rw-r--r--Lib/test/test_cmd_line.py22
-rw-r--r--Python/pythonrun.c20
2 files changed, 37 insertions, 5 deletions
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index db94a40..19089a4 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -13,18 +13,25 @@ def _spawn_python(*args):
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _kill_python(p):
+ return _kill_python_and_exit_code(p)[0]
+
+def _kill_python_and_exit_code(p):
p.stdin.close()
data = p.stdout.read()
p.stdout.close()
# try to cleanup the child so we don't appear to leak when running
# with regrtest -R. This should be a no-op on Windows.
subprocess._cleanup()
- return data
+ returncode = p.wait()
+ return data, returncode
class CmdLineTest(unittest.TestCase):
def start_python(self, *args):
+ return self.start_python_and_exit_code(*args)[0]
+
+ def start_python_and_exit_code(self, *args):
p = _spawn_python(*args)
- return _kill_python(p)
+ return _kill_python_and_exit_code(p)
def exit_code(self, *args):
cmd_line = [sys.executable, '-E']
@@ -61,6 +68,17 @@ class CmdLineTest(unittest.TestCase):
version = ('Python %d.%d' % sys.version_info[:2]).encode("ascii")
self.assertTrue(self.start_python('-V').startswith(version))
+ def test_verbose(self):
+ # -v causes imports to write to stderr. If the write to
+ # stderr itself causes an import to happen (for the output
+ # codec), a recursion loop can occur.
+ data, rc = self.start_python_and_exit_code('-v')
+ self.assertEqual(rc, 0)
+ self.assertTrue(b'stack overflow' not in data)
+ data, rc = self.start_python_and_exit_code('-vv')
+ self.assertEqual(rc, 0)
+ self.assertTrue(b'stack overflow' not in data)
+
def test_run_module(self):
# Test expected operation of the '-m' switch
# Switch needs an argument
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 6af7aec..d65d12d 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -512,7 +512,7 @@ Py_Finalize(void)
/* reset file system default encoding */
if (!Py_HasFileSystemDefaultEncoding) {
free((char*)Py_FileSystemDefaultEncoding);
- Py_FileSystemDefaultEncoding = NULL;
+ Py_FileSystemDefaultEncoding = NULL;
}
/* XXX Still allocated:
@@ -733,6 +733,7 @@ initstdio(void)
PyObject *m;
PyObject *std = NULL;
int status = 0, fd;
+ PyObject * encoding_attr;
/* Hack to avoid a nasty recursion issue when Python is invoked
in verbose mode: pre-import the Latin-1 and UTF-8 codecs */
@@ -823,6 +824,19 @@ initstdio(void)
goto error;
}
} /* if (fd < 0) */
+
+ /* Same as hack above, pre-import stderr's codec to avoid recursion
+ when import.c tries to write to stderr in verbose mode. */
+ encoding_attr = PyObject_GetAttrString(std, "encoding");
+ if (encoding_attr != NULL) {
+ const char * encoding;
+ encoding = PyUnicode_AsString(encoding_attr);
+ if (encoding != NULL) {
+ _PyCodec_Lookup(encoding);
+ }
+ }
+ PyErr_Clear(); /* Not a fatal error if codec isn't available */
+
PySys_SetObject("__stderr__", std);
PySys_SetObject("stderr", std);
Py_DECREF(std);
@@ -1900,8 +1914,8 @@ PyOS_CheckStack(void)
alloca(PYOS_STACK_MARGIN * sizeof(void*));
return 0;
} __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ?
- EXCEPTION_EXECUTE_HANDLER :
- EXCEPTION_CONTINUE_SEARCH) {
+ EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH) {
int errcode = _resetstkoflw();
if (errcode)
{