changeset: 102356:35bf83ff0828 user: Brett Cannon date: Fri Jul 15 10:41:49 2016 -0700 files: Lib/test/test_os.py Misc/NEWS Modules/posixmodule.c description: Issue #27512: Don't segfault when os.fspath() calls an object whose __fspath__() raises an exception. Thanks to Xiang Zhang for the patch. diff -r bae0d7389e96 -r 35bf83ff0828 Lib/test/test_os.py --- a/Lib/test/test_os.py Fri Jul 15 16:13:05 2016 +0300 +++ b/Lib/test/test_os.py Fri Jul 15 10:41:49 2016 -0700 @@ -3122,7 +3122,10 @@ 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 @@ 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 -r bae0d7389e96 -r 35bf83ff0828 Misc/NEWS --- a/Misc/NEWS Fri Jul 15 16:13:05 2016 +0300 +++ b/Misc/NEWS Fri Jul 15 10:41:49 2016 -0700 @@ -16,6 +16,9 @@ Library ------- +- Issue 27512: Fix a segfault when os.fspath() called a an __fspath__() method + that raised an exception. Patch by Xiang Zhang. + Tests ----- diff -r bae0d7389e96 -r 35bf83ff0828 Modules/posixmodule.c --- a/Modules/posixmodule.c Fri Jul 15 16:13:05 2016 +0300 +++ b/Modules/posixmodule.c Fri Jul 15 10:41:49 2016 -0700 @@ -12319,6 +12319,10 @@ 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, "