summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrett Cannon <brett@python.org>2016-07-15 10:41:49 -0700
committerBrett Cannon <brett@python.org>2016-07-15 10:41:49 -0700
commit03e4d0c5c6c7af36230ec72d1ad7842cf1e887ef (patch)
treebeb337cba81da571824cc2dac32e375090a983dd
parenteefb633becc8ba6ae7d30c04aaa01a5740b92cbb (diff)
downloadcpython-03e4d0c5c6c7af36230ec72d1ad7842cf1e887ef.tar.gz
Issue #27512: Don't segfault when os.fspath() calls an object whose
__fspath__() raises an exception. Thanks to Xiang Zhang for the patch.
-rw-r--r--Lib/test/test_os.py24
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/posixmodule.c4
3 files changed, 24 insertions, 7 deletions
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 4ade4aa9db..ecd2efb0e9 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -3122,7 +3122,10 @@ class TestPEP519(unittest.TestCase):
def __init__(self, path=''):
self.path = path
def __fspath__(self):
- return self.path
+ if isinstance(self.path, BaseException):
+ raise self.path
+ else:
+ return self.path
def test_return_bytes(self):
for b in b'hello', b'goodbye', b'some/path/and/file':
@@ -3145,18 +3148,25 @@ class TestPEP519(unittest.TestCase):
self.assertTrue(issubclass(self.PathLike, os.PathLike))
self.assertTrue(isinstance(self.PathLike(), os.PathLike))
- with self.assertRaises(TypeError):
- self.fspath(self.PathLike(42))
-
def test_garbage_in_exception_out(self):
vapor = type('blah', (), {})
for o in int, type, os, vapor():
self.assertRaises(TypeError, self.fspath, o)
def test_argument_required(self):
- with self.assertRaises(TypeError):
- self.fspath()
-
+ self.assertRaises(TypeError, self.fspath)
+
+ def test_bad_pathlike(self):
+ # __fspath__ returns a value other than str or bytes.
+ self.assertRaises(TypeError, self.fspath, self.PathLike(42))
+ # __fspath__ attribute that is not callable.
+ c = type('foo', (), {})
+ c.__fspath__ = 1
+ self.assertRaises(TypeError, self.fspath, c())
+ # __fspath__ raises an exception.
+ c.__fspath__ = lambda self: self.__not_exist
+ self.assertRaises(ZeroDivisionError, self.fspath,
+ self.PathLike(ZeroDivisionError))
# Only test if the C version is provided, otherwise TestPEP519 already tested
# the pure Python implementation.
diff --git a/Misc/NEWS b/Misc/NEWS
index de7c09c3c9..e3d01ba656 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -16,6 +16,9 @@ Core and Builtins
Library
-------
+- Issue 27512: Fix a segfault when os.fspath() called a an __fspath__() method
+ that raised an exception. Patch by Xiang Zhang.
+
Tests
-----
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 4c0f26e89c..7f16a83e78 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -12319,6 +12319,10 @@ PyOS_FSPath(PyObject *path)
path_repr = PyObject_CallFunctionObjArgs(func, NULL);
Py_DECREF(func);
+ if (NULL == path_repr) {
+ return NULL;
+ }
+
if (!(PyUnicode_Check(path_repr) || PyBytes_Check(path_repr))) {
PyErr_Format(PyExc_TypeError,
"expected %.200s.__fspath__() to return str or bytes, "