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

Skip to content

Commit c99b512

Browse files
Issue #15972: Fix error messages when os functions expecting a file name or
file descriptor receive the incorrect type.
2 parents 34bdeb5 + a2ad5c3 commit c99b512

3 files changed

Lines changed: 62 additions & 31 deletions

File tree

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
@@ -206,6 +206,9 @@ Core and Builtins
206206
Library
207207
-------
208208

209+
- Issue #15972: Fix error messages when os functions expecting a file name or
210+
file descriptor receive the incorrect type.
211+
209212
- Issue #8109: The ssl module now has support for server-side SNI, thanks
210213
to a :meth:`SSLContext.set_servername_callback` method. Patch by Daniel
211214
Black.

Modules/posixmodule.c

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

398398
static int
399-
_fd_converter(PyObject *o, int *p, int default_value) {
400-
long long_value;
401-
if (o == Py_None) {
402-
*p = default_value;
403-
return 1;
404-
}
405-
if (PyFloat_Check(o)) {
406-
PyErr_SetString(PyExc_TypeError,
407-
"integer argument expected, got float" );
399+
_fd_converter(PyObject *o, int *p, const char *allowed)
400+
{
401+
int overflow;
402+
long long_value = PyLong_AsLongAndOverflow(o, &overflow);
403+
if (PyFloat_Check(o) ||
404+
(long_value == -1 && !overflow && PyErr_Occurred())) {
405+
PyErr_Clear();
406+
PyErr_Format(PyExc_TypeError,
407+
"argument should be %s, not %.200s",
408+
allowed, Py_TYPE(o)->tp_name);
408409
return 0;
409410
}
410-
long_value = PyLong_AsLong(o);
411-
if (long_value == -1 && PyErr_Occurred())
412-
return 0;
413-
if (long_value > INT_MAX) {
411+
if (overflow > 0 || long_value > INT_MAX) {
414412
PyErr_SetString(PyExc_OverflowError,
415413
"signed integer is greater than maximum");
416414
return 0;
417415
}
418-
if (long_value < INT_MIN) {
416+
if (overflow < 0 || long_value < INT_MIN) {
419417
PyErr_SetString(PyExc_OverflowError,
420418
"signed integer is less than minimum");
421419
return 0;
@@ -425,8 +423,13 @@ _fd_converter(PyObject *o, int *p, int default_value) {
425423
}
426424

427425
static int
428-
dir_fd_converter(PyObject *o, void *p) {
429-
return _fd_converter(o, (int *)p, DEFAULT_DIR_FD);
426+
dir_fd_converter(PyObject *o, void *p)
427+
{
428+
if (o == Py_None) {
429+
*(int *)p = DEFAULT_DIR_FD;
430+
return 1;
431+
}
432+
return _fd_converter(o, (int *)p, "integer");
430433
}
431434

432435

@@ -603,17 +606,16 @@ path_converter(PyObject *o, void *p) {
603606
}
604607
else {
605608
PyErr_Clear();
606-
bytes = PyBytes_FromObject(o);
609+
if (PyObject_CheckBuffer(o))
610+
bytes = PyBytes_FromObject(o);
611+
else
612+
bytes = NULL;
607613
if (!bytes) {
608614
PyErr_Clear();
609615
if (path->allow_fd) {
610616
int fd;
611-
/*
612-
* note: _fd_converter always permits None.
613-
* but we've already done our None check.
614-
* so o cannot be None at this point.
615-
*/
616-
int result = _fd_converter(o, &fd, -1);
617+
int result = _fd_converter(o, &fd,
618+
"string, bytes or integer");
617619
if (result) {
618620
path->wide = NULL;
619621
path->narrow = NULL;
@@ -674,15 +676,17 @@ argument_unavailable_error(char *function_name, char *argument_name) {
674676
}
675677

676678
static int
677-
dir_fd_unavailable(PyObject *o, void *p) {
678-
int *dir_fd = (int *)p;
679-
int return_value = _fd_converter(o, dir_fd, DEFAULT_DIR_FD);
680-
if (!return_value)
679+
dir_fd_unavailable(PyObject *o, void *p)
680+
{
681+
int dir_fd;
682+
if (!dir_fd_converter(o, &dir_fd))
681683
return 0;
682-
if (*dir_fd == DEFAULT_DIR_FD)
683-
return 1;
684-
argument_unavailable_error(NULL, "dir_fd");
685-
return 0;
684+
if (dir_fd != DEFAULT_DIR_FD) {
685+
argument_unavailable_error(NULL, "dir_fd");
686+
return 0;
687+
}
688+
*(int *)p = dir_fd;
689+
return 1;
686690
}
687691

688692
static int

0 commit comments

Comments
 (0)