Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7ab4af0

Browse files
committed
Issue #13848: open() and the FileIO constructor now check for NUL characters in the file name.
Patch by Hynek Schlawack.
2 parents cdc878e + 1334884 commit 7ab4af0

6 files changed

Lines changed: 41 additions & 21 deletions

File tree

Include/unicodeobject.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,6 +1914,12 @@ PyAPI_FUNC(int) PyUnicode_Contains(
19141914
PyObject *element /* Element string */
19151915
);
19161916

1917+
/* Checks whether the string contains any NUL characters. */
1918+
1919+
#ifndef Py_LIMITED_API
1920+
PyAPI_FUNC(int) _PyUnicode_HasNULChars(PyObject *);
1921+
#endif
1922+
19171923
/* Checks whether argument is a valid identifier. */
19181924

19191925
PyAPI_FUNC(int) PyUnicode_IsIdentifier(PyObject *s);

Lib/test/test_fileio.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,11 @@ def testBytesOpen(self):
306306
finally:
307307
os.unlink(TESTFN)
308308

309+
def testConstructorHandlesNULChars(self):
310+
fn_with_NUL = 'foo\0bar'
311+
self.assertRaises(TypeError, _FileIO, fn_with_NUL, 'w')
312+
self.assertRaises(TypeError, _FileIO, bytes(fn_with_NUL, 'ascii'), 'w')
313+
309314
def testInvalidFd(self):
310315
self.assertRaises(ValueError, _FileIO, -10)
311316
self.assertRaises(OSError, _FileIO, make_bad_fd())

Lib/test/test_io.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,11 @@ def test_invalid_operations(self):
363363
self.assertRaises(exc, fp.seek, 1, self.SEEK_CUR)
364364
self.assertRaises(exc, fp.seek, -1, self.SEEK_END)
365365

366+
def test_open_handles_NUL_chars(self):
367+
fn_with_NUL = 'foo\0bar'
368+
self.assertRaises(TypeError, self.open, fn_with_NUL, 'w')
369+
self.assertRaises(TypeError, self.open, bytes(fn_with_NUL, 'ascii'), 'w')
370+
366371
def test_raw_file_io(self):
367372
with self.open(support.TESTFN, "wb", buffering=0) as f:
368373
self.assertEqual(f.readable(), False)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,9 @@ Core and Builtins
461461
Library
462462
-------
463463

464+
- Issue #13848: open() and the FileIO constructor now check for NUL
465+
characters in the file name. Patch by Hynek Schlawack.
466+
464467
- Issue #13806: The size check in audioop decompression functions was too
465468
strict and could reject valid compressed data. Patch by Oleg Plakhotnyuk.
466469

Modules/_io/fileio.c

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -258,35 +258,23 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
258258

259259
#ifdef MS_WINDOWS
260260
if (PyUnicode_Check(nameobj)) {
261+
int rv = _PyUnicode_HasNULChars(nameobj);
262+
if (rv) {
263+
if (rv != -1)
264+
PyErr_SetString(PyExc_TypeError, "embedded NUL character");
265+
return -1;
266+
}
261267
widename = PyUnicode_AsUnicode(nameobj);
262268
if (widename == NULL)
263269
return -1;
264270
} else
265271
#endif
266272
if (fd < 0)
267273
{
268-
if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) {
269-
Py_ssize_t namelen;
270-
if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0)
271-
return -1;
272-
}
273-
else {
274-
PyObject *u = PyUnicode_FromObject(nameobj);
275-
276-
if (u == NULL)
277-
return -1;
278-
279-
stringobj = PyUnicode_EncodeFSDefault(u);
280-
Py_DECREF(u);
281-
if (stringobj == NULL)
282-
return -1;
283-
if (!PyBytes_Check(stringobj)) {
284-
PyErr_SetString(PyExc_TypeError,
285-
"encoder failed to return bytes");
286-
goto error;
287-
}
288-
name = PyBytes_AS_STRING(stringobj);
274+
if (!PyUnicode_FSConverter(nameobj, &stringobj)) {
275+
return -1;
289276
}
277+
name = PyBytes_AS_STRING(stringobj);
290278
}
291279

292280
s = mode;

Objects/unicodeobject.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3574,6 +3574,19 @@ PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size)
35743574
}
35753575

35763576

3577+
int
3578+
_PyUnicode_HasNULChars(PyObject* s)
3579+
{
3580+
static PyObject *nul = NULL;
3581+
3582+
if (nul == NULL)
3583+
nul = PyUnicode_FromStringAndSize("\0", 1);
3584+
if (nul == NULL)
3585+
return -1;
3586+
return PyUnicode_Contains(s, nul);
3587+
}
3588+
3589+
35773590
int
35783591
PyUnicode_FSConverter(PyObject* arg, void* addr)
35793592
{

0 commit comments

Comments
 (0)