From a2ad5c3ad1bbf6d2088ff3ab2eb3bba51d096cc2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 7 Jan 2013 23:13:46 +0200 Subject: Issue #15972: Fix error messages when os functions expecting a file name or file descriptor receive the incorrect type. --- Lib/test/test_posix.py | 24 ++++++++++++++++++ Misc/NEWS | 3 +++ Modules/posixmodule.c | 66 ++++++++++++++++++++++++++------------------------ 3 files changed, 62 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index f4e8aba..26d5570 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -358,12 +358,28 @@ class PosixTester(unittest.TestCase): try: self.assertTrue(posix.fstat(fp.fileno())) self.assertTrue(posix.stat(fp.fileno())) + + self.assertRaisesRegex(TypeError, + 'should be string, bytes or integer, not', + posix.stat, float(fp.fileno())) finally: fp.close() def test_stat(self): if hasattr(posix, 'stat'): self.assertTrue(posix.stat(support.TESTFN)) + self.assertTrue(posix.stat(os.fsencode(support.TESTFN))) + self.assertTrue(posix.stat(bytearray(os.fsencode(support.TESTFN)))) + + self.assertRaisesRegex(TypeError, + 'can\'t specify None for path argument', + posix.stat, None) + self.assertRaisesRegex(TypeError, + 'should be string, bytes or integer, not', + posix.stat, list(support.TESTFN)) + self.assertRaisesRegex(TypeError, + 'should be string, bytes or integer, not', + posix.stat, list(os.fsencode(support.TESTFN))) @unittest.skipUnless(hasattr(posix, 'mkfifo'), "don't have mkfifo()") def test_mkfifo(self): @@ -714,6 +730,14 @@ class PosixTester(unittest.TestCase): s1 = posix.stat(support.TESTFN) s2 = posix.stat(support.TESTFN, dir_fd=f) self.assertEqual(s1, s2) + s2 = posix.stat(support.TESTFN, dir_fd=None) + self.assertEqual(s1, s2) + self.assertRaisesRegex(TypeError, 'should be integer, not', + posix.stat, support.TESTFN, dir_fd=posix.getcwd()) + self.assertRaisesRegex(TypeError, 'should be integer, not', + posix.stat, support.TESTFN, dir_fd=float(f)) + self.assertRaises(OverflowError, + posix.stat, support.TESTFN, dir_fd=10**20) finally: posix.close(f) diff --git a/Misc/NEWS b/Misc/NEWS index 2d07675..00fc9a6 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -136,6 +136,9 @@ Core and Builtins Library ------- +- Issue #15972: Fix error messages when os functions expecting a file name or + file descriptor receive the incorrect type. + - Issue #16828: Fix error incorrectly raised by bz2.compress(b'') and bz2.BZ2Compressor.compress(b''). Initial patch by Martin Packman. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 177be70..25330a0 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -427,26 +427,24 @@ win32_warn_bytes_api() #endif static int -_fd_converter(PyObject *o, int *p, int default_value) { - long long_value; - if (o == Py_None) { - *p = default_value; - return 1; - } - if (PyFloat_Check(o)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); +_fd_converter(PyObject *o, int *p, const char *allowed) +{ + int overflow; + long long_value = PyLong_AsLongAndOverflow(o, &overflow); + if (PyFloat_Check(o) || + (long_value == -1 && !overflow && PyErr_Occurred())) { + PyErr_Clear(); + PyErr_Format(PyExc_TypeError, + "argument should be %s, not %.200s", + allowed, Py_TYPE(o)->tp_name); return 0; } - long_value = PyLong_AsLong(o); - if (long_value == -1 && PyErr_Occurred()) - return 0; - if (long_value > INT_MAX) { + if (overflow > 0 || long_value > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "signed integer is greater than maximum"); return 0; } - if (long_value < INT_MIN) { + if (overflow < 0 || long_value < INT_MIN) { PyErr_SetString(PyExc_OverflowError, "signed integer is less than minimum"); return 0; @@ -456,8 +454,13 @@ _fd_converter(PyObject *o, int *p, int default_value) { } static int -dir_fd_converter(PyObject *o, void *p) { - return _fd_converter(o, (int *)p, DEFAULT_DIR_FD); +dir_fd_converter(PyObject *o, void *p) +{ + if (o == Py_None) { + *(int *)p = DEFAULT_DIR_FD; + return 1; + } + return _fd_converter(o, (int *)p, "integer"); } @@ -634,17 +637,16 @@ path_converter(PyObject *o, void *p) { } else { PyErr_Clear(); - bytes = PyBytes_FromObject(o); + if (PyObject_CheckBuffer(o)) + bytes = PyBytes_FromObject(o); + else + bytes = NULL; if (!bytes) { PyErr_Clear(); if (path->allow_fd) { int fd; - /* - * note: _fd_converter always permits None. - * but we've already done our None check. - * so o cannot be None at this point. - */ - int result = _fd_converter(o, &fd, -1); + int result = _fd_converter(o, &fd, + "string, bytes or integer"); if (result) { path->wide = NULL; path->narrow = NULL; @@ -705,15 +707,17 @@ argument_unavailable_error(char *function_name, char *argument_name) { } static int -dir_fd_unavailable(PyObject *o, void *p) { - int *dir_fd = (int *)p; - int return_value = _fd_converter(o, dir_fd, DEFAULT_DIR_FD); - if (!return_value) +dir_fd_unavailable(PyObject *o, void *p) +{ + int dir_fd; + if (!dir_fd_converter(o, &dir_fd)) return 0; - if (*dir_fd == DEFAULT_DIR_FD) - return 1; - argument_unavailable_error(NULL, "dir_fd"); - return 0; + if (dir_fd != DEFAULT_DIR_FD) { + argument_unavailable_error(NULL, "dir_fd"); + return 0; + } + *(int *)p = dir_fd; + return 1; } static int -- cgit v0.12