From 1334884ff2f5a3968e6a26157f869b4ca5de189b Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 29 Jan 2012 18:36:34 +0100 Subject: Issue #13848: open() and the FileIO constructor now check for NUL characters in the file name. Patch by Hynek Schlawack. --- Include/unicodeobject.h | 6 ++++++ Lib/test/test_fileio.py | 5 +++++ Lib/test/test_io.py | 5 +++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/_io/fileio.c | 33 +++++++++++---------------------- Objects/unicodeobject.c | 13 +++++++++++++ 7 files changed, 44 insertions(+), 22 deletions(-) diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h index 477f526..379a90c 100644 --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1501,6 +1501,12 @@ PyAPI_FUNC(int) PyUnicode_Contains( PyObject *element /* Element string */ ); +/* Checks whether the string contains any NUL characters. */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyUnicode_HasNULChars(PyObject *); +#endif + /* Checks whether argument is a valid identifier. */ PyAPI_FUNC(int) PyUnicode_IsIdentifier(PyObject *s); diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py index 103365d..3588fb4 100644 --- a/Lib/test/test_fileio.py +++ b/Lib/test/test_fileio.py @@ -305,6 +305,11 @@ class OtherFileTests(unittest.TestCase): finally: os.unlink(TESTFN) + def testConstructorHandlesNULChars(self): + fn_with_NUL = 'foo\0bar' + self.assertRaises(TypeError, _FileIO, fn_with_NUL, 'w') + self.assertRaises(TypeError, _FileIO, bytes(fn_with_NUL, 'ascii'), 'w') + def testInvalidFd(self): self.assertRaises(ValueError, _FileIO, -10) self.assertRaises(OSError, _FileIO, make_bad_fd()) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index df7ca15..ea82cea 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -363,6 +363,11 @@ class IOTest(unittest.TestCase): self.assertRaises(exc, fp.seek, 1, self.SEEK_CUR) self.assertRaises(exc, fp.seek, -1, self.SEEK_END) + def test_open_handles_NUL_chars(self): + fn_with_NUL = 'foo\0bar' + self.assertRaises(TypeError, self.open, fn_with_NUL, 'w') + self.assertRaises(TypeError, self.open, bytes(fn_with_NUL, 'ascii'), 'w') + def test_raw_file_io(self): with self.open(support.TESTFN, "wb", buffering=0) as f: self.assertEqual(f.readable(), False) diff --git a/Misc/ACKS b/Misc/ACKS index 8117d80..48df3fb 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -811,6 +811,7 @@ Michael Scharf Andreas Schawo Neil Schemenauer David Scherer +Hynek Schlawack Bob Schmertz Gregor Schmid Ralf Schmitt diff --git a/Misc/NEWS b/Misc/NEWS index e02a7c9..1287d2d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -111,6 +111,9 @@ Core and Builtins Library ------- +- Issue #13848: open() and the FileIO constructor now check for NUL + characters in the file name. Patch by Hynek Schlawack. + - Issue #13806: The size check in audioop decompression functions was too strict and could reject valid compressed data. Patch by Oleg Plakhotnyuk. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index f39f8b0..d5b03ee 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -253,34 +253,23 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) } #ifdef MS_WINDOWS - if (PyUnicode_Check(nameobj)) + if (PyUnicode_Check(nameobj)) { + int rv = _PyUnicode_HasNULChars(nameobj); + if (rv) { + if (rv != -1) + PyErr_SetString(PyExc_TypeError, "embedded NUL character"); + return -1; + } widename = PyUnicode_AS_UNICODE(nameobj); + } if (widename == NULL) #endif if (fd < 0) { - if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) { - Py_ssize_t namelen; - if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0) - return -1; - } - else { - PyObject *u = PyUnicode_FromObject(nameobj); - - if (u == NULL) - return -1; - - stringobj = PyUnicode_EncodeFSDefault(u); - Py_DECREF(u); - if (stringobj == NULL) - return -1; - if (!PyBytes_Check(stringobj)) { - PyErr_SetString(PyExc_TypeError, - "encoder failed to return bytes"); - goto error; - } - name = PyBytes_AS_STRING(stringobj); + if (!PyUnicode_FSConverter(nameobj, &stringobj)) { + return -1; } + name = PyBytes_AS_STRING(stringobj); } s = mode; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 20528b9..f51d4d0 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1867,6 +1867,19 @@ PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size) int +_PyUnicode_HasNULChars(PyObject* s) +{ + static PyObject *nul = NULL; + + if (nul == NULL) + nul = PyUnicode_FromStringAndSize("\0", 1); + if (nul == NULL) + return -1; + return PyUnicode_Contains(s, nul); +} + + +int PyUnicode_FSConverter(PyObject* arg, void* addr) { PyObject *output = NULL; -- cgit v0.12