From 9305d83425e2ec63b2769336907dd07b3151cd5f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 18 Jun 2016 13:53:36 +0300 Subject: Issue #26754: PyUnicode_FSDecoder() accepted a filename argument encoded as an iterable of integers. Now only strings and byte-like objects are accepted. --- Lib/test/test_compile.py | 7 +++++++ Lib/test/test_parser.py | 16 ++++++++++++++++ Lib/test/test_symtable.py | 6 ++++++ Lib/test/test_zipimport.py | 15 +++++++++++++++ Misc/NEWS | 11 +++++++++++ Objects/unicodeobject.c | 8 +++++++- 6 files changed, 62 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e0fdee3..824e843 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -472,6 +472,13 @@ if 1: d = {f(): f(), f(): f()} self.assertEqual(d, {1: 2, 3: 4}) + def test_compile_filename(self): + for filename in ('file.py', b'file.py', + bytearray(b'file.py'), memoryview(b'file.py')): + code = compile('pass', filename, 'exec') + self.assertEqual(code.co_filename, 'file.py') + self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec') + @support.cpython_only def test_same_filename_used(self): s = """def f(): pass\ndef g(): pass""" diff --git a/Lib/test/test_parser.py b/Lib/test/test_parser.py index 3d301b4..ab6577f 100644 --- a/Lib/test/test_parser.py +++ b/Lib/test/test_parser.py @@ -627,6 +627,22 @@ class CompileTestCase(unittest.TestCase): code2 = parser.compilest(st) self.assertEqual(eval(code2), -3) + def test_compile_filename(self): + st = parser.expr('a + 5') + code = parser.compilest(st) + self.assertEqual(code.co_filename, '') + code = st.compile() + self.assertEqual(code.co_filename, '') + for filename in ('file.py', b'file.py', + bytearray(b'file.py'), memoryview(b'file.py')): + code = parser.compilest(st, filename) + self.assertEqual(code.co_filename, 'file.py') + code = st.compile(filename) + self.assertEqual(code.co_filename, 'file.py') + self.assertRaises(TypeError, parser.compilest, st, list(b'file.py')) + self.assertRaises(TypeError, st.compile, list(b'file.py')) + + class ParserStackLimitTestCase(unittest.TestCase): """try to push the parser to/over its limits. see http://bugs.python.org/issue1881 for a discussion diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index e5e7b83..c5d7fac 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -157,6 +157,12 @@ class SymtableTest(unittest.TestCase): self.fail("no SyntaxError for %r" % (brokencode,)) checkfilename("def f(x): foo)(") # parse-time checkfilename("def f(x): global x") # symtable-build-time + symtable.symtable("pass", b"spam", "exec") + with self.assertRaises(TypeError): + symtable.symtable("pass", bytearray(b"spam"), "exec") + symtable.symtable("pass", memoryview(b"spam"), "exec") + with self.assertRaises(TypeError): + symtable.symtable("pass", list(b"spam"), "exec") def test_eval(self): symbols = symtable.symtable("42", "?", "eval") diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py index 0da5906..8e5e12d 100644 --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -600,6 +600,19 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): finally: os.remove(filename) + def testBytesPath(self): + filename = support.TESTFN + ".zip" + self.addCleanup(support.unlink, filename) + with ZipFile(filename, "w") as z: + zinfo = ZipInfo(TESTMOD + ".py", time.localtime(NOW)) + zinfo.compress_type = self.compression + z.writestr(zinfo, test_src) + + zipimport.zipimporter(filename) + zipimport.zipimporter(os.fsencode(filename)) + zipimport.zipimporter(bytearray(os.fsencode(filename))) + zipimport.zipimporter(memoryview(os.fsencode(filename))) + @support.requires_zlib class CompressedZipImportTestCase(UncompressedZipImportTestCase): @@ -620,6 +633,8 @@ class BadFileZipImportTestCase(unittest.TestCase): def testBadArgs(self): self.assertRaises(TypeError, zipimport.zipimporter, None) self.assertRaises(TypeError, zipimport.zipimporter, TESTMOD, kwd=None) + self.assertRaises(TypeError, zipimport.zipimporter, + list(os.fsencode(TESTMOD))) def testFilenameTooLong(self): self.assertZipFailure('A' * 33000) diff --git a/Misc/NEWS b/Misc/NEWS index 5dff4db..3c6d3ae 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Core and Builtins Library ------- +- Issue #26754: Some functions (compile() etc) accepted a filename argument + encoded as an iterable of integers. Now only strings and byte-like objects + are accepted. + - Issue #27048: Prevents distutils failing on Windows when environment variables contain non-ASCII characters @@ -43,6 +47,13 @@ Library - Issue #26930: Update Windows builds to use OpenSSL 1.0.2h. +C API +----- + +- Issue #26754: PyUnicode_FSDecoder() accepted a filename argument encoded as + an iterable of integers. Now only strings and byte-like objects are accepted. + + What's New in Python 3.5.2 final? ================================= diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index f11a082..1fcc83e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3666,7 +3666,7 @@ PyUnicode_FSDecoder(PyObject* arg, void* addr) output = arg; Py_INCREF(output); } - else { + else if (PyObject_CheckBuffer(arg)) { arg = PyBytes_FromObject(arg); if (!arg) return 0; @@ -3681,6 +3681,12 @@ PyUnicode_FSDecoder(PyObject* arg, void* addr) return 0; } } + else { + PyErr_Format(PyExc_TypeError, + "path should be string or bytes, not %.200s", + Py_TYPE(arg)->tp_name); + return 0; + } if (PyUnicode_READY(output) == -1) { Py_DECREF(output); return 0; -- cgit v0.12