diff -r a88310d86455 Lib/test/test_posix.py --- a/Lib/test/test_posix.py Sun Apr 14 19:22:47 2013 +0200 +++ b/Lib/test/test_posix.py Mon Apr 15 02:53:48 2013 -0700 @@ -361,7 +361,7 @@ self.assertTrue(posix.stat(fp.fileno())) self.assertRaisesRegex(TypeError, - 'should be string, bytes or integer, not', + 'must be string, bytes or integer, not', posix.stat, float(fp.fileno())) finally: fp.close() @@ -376,10 +376,10 @@ 'can\'t specify None for path argument', posix.stat, None) self.assertRaisesRegex(TypeError, - 'should be string, bytes or integer, not', + 'must be string, bytes or integer, not', posix.stat, list(support.TESTFN)) self.assertRaisesRegex(TypeError, - 'should be string, bytes or integer, not', + 'must be string, bytes or integer, not', posix.stat, list(os.fsencode(support.TESTFN))) @unittest.skipUnless(hasattr(posix, 'mkfifo'), "don't have mkfifo()") @@ -780,9 +780,9 @@ self.assertEqual(s1, s2) s2 = posix.stat(support.TESTFN, dir_fd=None) self.assertEqual(s1, s2) - self.assertRaisesRegex(TypeError, 'should be integer, not', + self.assertRaisesRegex(TypeError, 'must be integer, not', posix.stat, support.TESTFN, dir_fd=posix.getcwd()) - self.assertRaisesRegex(TypeError, 'should be integer, not', + self.assertRaisesRegex(TypeError, 'must be integer, not', posix.stat, support.TESTFN, dir_fd=float(f)) self.assertRaises(OverflowError, posix.stat, support.TESTFN, dir_fd=10**20) diff -r a88310d86455 Modules/posixmodule.c --- a/Modules/posixmodule.c Sun Apr 14 19:22:47 2013 +0200 +++ b/Modules/posixmodule.c Mon Apr 15 02:53:48 2013 -0700 @@ -405,108 +405,178 @@ int _Py_Uid_Converter(PyObject *obj, void *p) { + uid_t uid; + PyObject *index; int overflow; long result; - if (PyFloat_Check(obj)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float"); + unsigned long uresult; + + index = PyNumber_Index(obj); + if (index == NULL) { + PyErr_Format(PyExc_TypeError, + "uid must be integer, not %.200s", + obj->ob_type->tp_name); return 0; } - result = PyLong_AsLongAndOverflow(obj, &overflow); + + /* + * We can't predict whether uid_t is signed or unsigned + * on the local platform, nor whether it's smaller than + * or the same size as a long. So a bit of defensive + * programming is in order. Start with interpreting + * the value the user passed in as a signed long and + * see if it works. + */ + + result = PyLong_AsLongAndOverflow(index, &overflow); + + if (!overflow) { + if (PyErr_Occurred()) + goto fail; + + /* -1 is the only permissable negative number... */ + if (result < -1) + goto underflow; + + uid = (uid_t)result; + + /* ... but it may not pass the next test, so handle it special. */ + if (result == -1) + goto success; + + if (sizeof(uid_t) < sizeof(long) && + (long)uid != result) + goto underflow; + goto success; + } + if (overflow < 0) - goto OverflowDown; - if (!overflow && result == -1) { - /* error or -1 */ - if (PyErr_Occurred()) - return 0; - *(uid_t *)p = (uid_t)-1; - } - else { - /* unsigned uid_t */ - unsigned long uresult; - if (overflow > 0) { - uresult = PyLong_AsUnsignedLong(obj); - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - goto OverflowUp; - return 0; - } - if ((uid_t)uresult == (uid_t)-1) - goto OverflowUp; - } else { - if (result < 0) - goto OverflowDown; - uresult = result; - } - if (sizeof(uid_t) < sizeof(long) && - (unsigned long)(uid_t)uresult != uresult) - goto OverflowUp; - *(uid_t *)p = (uid_t)uresult; - } + goto underflow; + + /* + * Okay, the value overflowed a signed long. If it + * fits in an *unsigned* long, it may still be okay. + */ + uresult = PyLong_AsUnsignedLong(index); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + goto overflow; + goto fail; + } + + uid = (uid_t)uresult; + + if (sizeof(uid_t) < sizeof(long) && + (unsigned long)uid != uresult) + goto overflow; + /* fallthrough */ + +success: + Py_DECREF(index); + *(uid_t *)p = uid; return 1; -OverflowDown: +underflow: PyErr_SetString(PyExc_OverflowError, - "user id is less than minimum"); - return 0; - -OverflowUp: + "uid is less than minimum"); + goto fail; + +overflow: PyErr_SetString(PyExc_OverflowError, - "user id is greater than maximum"); + "uid is greater than maximum"); + /* fallthrough */ + +fail: + Py_DECREF(index); return 0; } int _Py_Gid_Converter(PyObject *obj, void *p) { + gid_t gid; + PyObject *index; int overflow; long result; - if (PyFloat_Check(obj)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float"); + unsigned long uresult; + + index = PyNumber_Index(obj); + if (index == NULL) { + PyErr_Format(PyExc_TypeError, + "gid must be integer, not %.200s", + obj->ob_type->tp_name); return 0; } - result = PyLong_AsLongAndOverflow(obj, &overflow); + + /* + * We can't predict whether gid_t is signed or unsigned + * on the local platform, nor whether it's smaller than + * or the same size as a long. So a bit of defensive + * programming is in order. Start with interpreting + * the value the user passed in as a signed long and + * see if it works. + */ + + result = PyLong_AsLongAndOverflow(index, &overflow); + + if (!overflow) { + if (PyErr_Occurred()) + goto fail; + + /* -1 is the only permissable negative number... */ + if (result < -1) + goto underflow; + + gid = (gid_t)result; + + /* ... but it may not pass the next test, so handle it special. */ + if (result == -1) + goto success; + + if (sizeof(gid_t) < sizeof(long) && + (long)gid != result) + goto underflow; + goto success; + } + if (overflow < 0) - goto OverflowDown; - if (!overflow && result == -1) { - /* error or -1 */ - if (PyErr_Occurred()) - return 0; - *(gid_t *)p = (gid_t)-1; - } - else { - /* unsigned gid_t */ - unsigned long uresult; - if (overflow > 0) { - uresult = PyLong_AsUnsignedLong(obj); - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - goto OverflowUp; - return 0; - } - if ((gid_t)uresult == (gid_t)-1) - goto OverflowUp; - } else { - if (result < 0) - goto OverflowDown; - uresult = result; - } - if (sizeof(gid_t) < sizeof(long) && - (unsigned long)(gid_t)uresult != uresult) - goto OverflowUp; - *(gid_t *)p = (gid_t)uresult; - } + goto underflow; + + /* + * Okay, the value overflowed a signed long. If it + * fits in an *unsigned* long, it may still be okay. + */ + uresult = PyLong_AsUnsignedLong(index); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + goto overflow; + goto fail; + } + + gid = (gid_t)uresult; + + if (sizeof(gid_t) < sizeof(long) && + (unsigned long)gid != uresult) + goto overflow; + /* fallthrough */ + +success: + Py_DECREF(index); + *(uid_t *)p = gid; return 1; -OverflowDown: +underflow: PyErr_SetString(PyExc_OverflowError, - "group id is less than minimum"); - return 0; - -OverflowUp: + "gid is less than minimum"); + goto fail; + +overflow: PyErr_SetString(PyExc_OverflowError, - "group id is greater than maximum"); + "gid is greater than maximum"); + /* fallthrough */ + +fail: + Py_DECREF(index); return 0; } #endif /* MS_WINDOWS */ @@ -529,25 +599,29 @@ _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(); + long long_value; + + PyObject *index = PyNumber_Index(o); + if (index == NULL) { PyErr_Format(PyExc_TypeError, - "argument should be %s, not %.200s", - allowed, Py_TYPE(o)->tp_name); + "argument must be %s, not %.200s", + allowed, o->ob_type->tp_name); return 0; } + + long_value = PyLong_AsLongAndOverflow(index, &overflow); + Py_DECREF(index); if (overflow > 0 || long_value > INT_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed integer is greater than maximum"); + "fd is greater than maximum"); return 0; } if (overflow < 0 || long_value < INT_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed integer is less than minimum"); + "fd is less than minimum"); return 0; } + *p = (int)long_value; return 1; }