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

Skip to content

Commit a2ad5c3

Browse files
Issue #15972: Fix error messages when os functions expecting a file name or
file descriptor receive the incorrect type.
1 parent 0e82fd1 commit a2ad5c3

File tree

3 files changed

+62
-31
lines changed

3 files changed

+62
-31
lines changed

Lib/test/test_posix.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,28 @@ def test_fstat(self):
358358
try:
359359
self.assertTrue(posix.fstat(fp.fileno()))
360360
self.assertTrue(posix.stat(fp.fileno()))
361+
362+
self.assertRaisesRegex(TypeError,
363+
'should be string, bytes or integer, not',
364+
posix.stat, float(fp.fileno()))
361365
finally:
362366
fp.close()
363367

364368
def test_stat(self):
365369
if hasattr(posix, 'stat'):
366370
self.assertTrue(posix.stat(support.TESTFN))
371+
self.assertTrue(posix.stat(os.fsencode(support.TESTFN)))
372+
self.assertTrue(posix.stat(bytearray(os.fsencode(support.TESTFN))))
373+
374+
self.assertRaisesRegex(TypeError,
375+
'can\'t specify None for path argument',
376+
posix.stat, None)
377+
self.assertRaisesRegex(TypeError,
378+
'should be string, bytes or integer, not',
379+
posix.stat, list(support.TESTFN))
380+
self.assertRaisesRegex(TypeError,
381+
'should be string, bytes or integer, not',
382+
posix.stat, list(os.fsencode(support.TESTFN)))
367383

368384
@unittest.skipUnless(hasattr(posix, 'mkfifo'), "don't have mkfifo()")
369385
def test_mkfifo(self):
@@ -714,6 +730,14 @@ def test_stat_dir_fd(self):
714730
s1 = posix.stat(support.TESTFN)
715731
s2 = posix.stat(support.TESTFN, dir_fd=f)
716732
self.assertEqual(s1, s2)
733+
s2 = posix.stat(support.TESTFN, dir_fd=None)
734+
self.assertEqual(s1, s2)
735+
self.assertRaisesRegex(TypeError, 'should be integer, not',
736+
posix.stat, support.TESTFN, dir_fd=posix.getcwd())
737+
self.assertRaisesRegex(TypeError, 'should be integer, not',
738+
posix.stat, support.TESTFN, dir_fd=float(f))
739+
self.assertRaises(OverflowError,
740+
posix.stat, support.TESTFN, dir_fd=10**20)
717741
finally:
718742
posix.close(f)
719743

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ Core and Builtins
136136
Library
137137
-------
138138

139+
- Issue #15972: Fix error messages when os functions expecting a file name or
140+
file descriptor receive the incorrect type.
141+
139142
- Issue #16828: Fix error incorrectly raised by bz2.compress(b'') and
140143
bz2.BZ2Compressor.compress(b''). Initial patch by Martin Packman.
141144

Modules/posixmodule.c

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -427,26 +427,24 @@ win32_warn_bytes_api()
427427
#endif
428428

429429
static int
430-
_fd_converter(PyObject *o, int *p, int default_value) {
431-
long long_value;
432-
if (o == Py_None) {
433-
*p = default_value;
434-
return 1;
435-
}
436-
if (PyFloat_Check(o)) {
437-
PyErr_SetString(PyExc_TypeError,
438-
"integer argument expected, got float" );
430+
_fd_converter(PyObject *o, int *p, const char *allowed)
431+
{
432+
int overflow;
433+
long long_value = PyLong_AsLongAndOverflow(o, &overflow);
434+
if (PyFloat_Check(o) ||
435+
(long_value == -1 && !overflow && PyErr_Occurred())) {
436+
PyErr_Clear();
437+
PyErr_Format(PyExc_TypeError,
438+
"argument should be %s, not %.200s",
439+
allowed, Py_TYPE(o)->tp_name);
439440
return 0;
440441
}
441-
long_value = PyLong_AsLong(o);
442-
if (long_value == -1 && PyErr_Occurred())
443-
return 0;
444-
if (long_value > INT_MAX) {
442+
if (overflow > 0 || long_value > INT_MAX) {
445443
PyErr_SetString(PyExc_OverflowError,
446444
"signed integer is greater than maximum");
447445
return 0;
448446
}
449-
if (long_value < INT_MIN) {
447+
if (overflow < 0 || long_value < INT_MIN) {
450448
PyErr_SetString(PyExc_OverflowError,
451449
"signed integer is less than minimum");
452450
return 0;
@@ -456,8 +454,13 @@ _fd_converter(PyObject *o, int *p, int default_value) {
456454
}
457455

458456
static int
459-
dir_fd_converter(PyObject *o, void *p) {
460-
return _fd_converter(o, (int *)p, DEFAULT_DIR_FD);
457+
dir_fd_converter(PyObject *o, void *p)
458+
{
459+
if (o == Py_None) {
460+
*(int *)p = DEFAULT_DIR_FD;
461+
return 1;
462+
}
463+
return _fd_converter(o, (int *)p, "integer");
461464
}
462465

463466

@@ -634,17 +637,16 @@ path_converter(PyObject *o, void *p) {
634637
}
635638
else {
636639
PyErr_Clear();
637-
bytes = PyBytes_FromObject(o);
640+
if (PyObject_CheckBuffer(o))
641+
bytes = PyBytes_FromObject(o);
642+
else
643+
bytes = NULL;
638644
if (!bytes) {
639645
PyErr_Clear();
640646
if (path->allow_fd) {
641647
int fd;
642-
/*
643-
* note: _fd_converter always permits None.
644-
* but we've already done our None check.
645-
* so o cannot be None at this point.
646-
*/
647-
int result = _fd_converter(o, &fd, -1);
648+
int result = _fd_converter(o, &fd,
649+
"string, bytes or integer");
648650
if (result) {
649651
path->wide = NULL;
650652
path->narrow = NULL;
@@ -705,15 +707,17 @@ argument_unavailable_error(char *function_name, char *argument_name) {
705707
}
706708

707709
static int
708-
dir_fd_unavailable(PyObject *o, void *p) {
709-
int *dir_fd = (int *)p;
710-
int return_value = _fd_converter(o, dir_fd, DEFAULT_DIR_FD);
711-
if (!return_value)
710+
dir_fd_unavailable(PyObject *o, void *p)
711+
{
712+
int dir_fd;
713+
if (!dir_fd_converter(o, &dir_fd))
712714
return 0;
713-
if (*dir_fd == DEFAULT_DIR_FD)
714-
return 1;
715-
argument_unavailable_error(NULL, "dir_fd");
716-
return 0;
715+
if (dir_fd != DEFAULT_DIR_FD) {
716+
argument_unavailable_error(NULL, "dir_fd");
717+
return 0;
718+
}
719+
*(int *)p = dir_fd;
720+
return 1;
717721
}
718722

719723
static int

0 commit comments

Comments
 (0)