cpython: 13e2e44db99d (original) (raw)
Mercurial > cpython
changeset 81505:13e2e44db99d
Issue #15989: Fix several occurrences of integer overflow when result of PyLong_AsLong() narrowed to int without checks. [#15989]
line wrap: on
line diff
--- a/Include/longobject.h +++ b/Include/longobject.h @@ -26,6 +26,9 @@ PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t( PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyLong_AsInt(PyObject *); +#endif PyAPI_FUNC(PyObject ) PyLong_GetInfo(void); / It may be useful in the future. I've added it in the PyInt -> PyLong
--- a/Lib/ctypes/test/test_structures.py +++ b/Lib/ctypes/test/test_structures.py @@ -1,6 +1,7 @@ import unittest from ctypes import * from struct import calcsize +import _testcapi class SubclassesTest(unittest.TestCase): def test_subclass(self): @@ -199,6 +200,14 @@ class StructureTestCase(unittest.TestCas "pack": -1} self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
# Issue 15989[](#l2.15)
d = {"_fields_": [("a", c_byte)],[](#l2.16)
"_pack_": _testcapi.INT_MAX + 1}[](#l2.17)
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)[](#l2.18)
d = {"_fields_": [("a", c_byte)],[](#l2.19)
"_pack_": _testcapi.UINT_MAX + 2}[](#l2.20)
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)[](#l2.21)
+ def test_initializers(self): class Person(Structure): fields = [("name", c_char*6),
--- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -5,6 +5,7 @@ Common tests shared by test_str, test_un import unittest, string, sys, struct from test import support from collections import UserList +import _testcapi class Sequence: def init(self, seq='wxyz'): self.seq = seq @@ -1206,6 +1207,16 @@ class MixinStrUnicodeUserStringTest: self.checkraises(ValueError, '%%%df' % (264), 'mod', (3.2)) self.checkraises(ValueError, '%%.%df' % (264), 'mod', (3.2))
self.checkraises(OverflowError, '%*s', '__mod__',[](#l3.15)
(_testcapi.PY_SSIZE_T_MAX + 1, ''))[](#l3.16)
self.checkraises(OverflowError, '%.*f', '__mod__',[](#l3.17)
(_testcapi.INT_MAX + 1, 1. / 7))[](#l3.18)
# Issue 15989[](#l3.19)
self.checkraises(OverflowError, '%*s', '__mod__',[](#l3.20)
(1 << (_testcapi.PY_SSIZE_T_MAX.bit_length() + 1), ''))[](#l3.21)
self.checkraises(OverflowError, '%.*f', '__mod__',[](#l3.22)
(_testcapi.UINT_MAX + 1, 1. / 7))[](#l3.23)
+ class X(object): pass self.checkraises(TypeError, 'abc', 'mod', X())
--- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -3,6 +3,7 @@ import os import struct import sys +import _testcapi import unittest from test.support import verbose, TESTFN, unlink, run_unittest, import_module @@ -69,6 +70,26 @@ class TestFcntl(unittest.TestCase): rv = fcntl.fcntl(self.f, fcntl.F_SETLKW, lockdata) self.f.close()
- def test_fcntl_bad_file(self):
class F:[](#l4.16)
def __init__(self, fn):[](#l4.17)
self.fn = fn[](#l4.18)
def fileno(self):[](#l4.19)
return self.fn[](#l4.20)
self.assertRaises(ValueError, fcntl.fcntl, -1, fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.21)
self.assertRaises(ValueError, fcntl.fcntl, F(-1), fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.22)
self.assertRaises(TypeError, fcntl.fcntl, 'spam', fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.23)
self.assertRaises(TypeError, fcntl.fcntl, F('spam'), fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.24)
# Issue 15989[](#l4.25)
self.assertRaises(OverflowError, fcntl.fcntl, _testcapi.INT_MAX + 1,[](#l4.26)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.27)
self.assertRaises(OverflowError, fcntl.fcntl, F(_testcapi.INT_MAX + 1),[](#l4.28)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.29)
self.assertRaises(OverflowError, fcntl.fcntl, _testcapi.INT_MIN - 1,[](#l4.30)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.31)
self.assertRaises(OverflowError, fcntl.fcntl, F(_testcapi.INT_MIN - 1),[](#l4.32)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l4.33)
+ def test_fcntl_64_bit(self): # Issue #1309352: fcntl shouldn't fail when the third arg fits in a # C 'long' but not in a C 'int'.
--- a/Lib/test/test_fileio.py +++ b/Lib/test/test_fileio.py @@ -8,6 +8,7 @@ import unittest from array import array from weakref import proxy from functools import wraps +import _testcapi from test.support import TESTFN, check_warnings, run_unittest, make_bad_fd from collections import UserList @@ -347,6 +348,9 @@ class OtherFileTests(unittest.TestCase): if sys.platform == 'win32': import msvcrt self.assertRaises(OSError, msvcrt.get_osfhandle, make_bad_fd())
# Issue 15989[](#l5.15)
self.assertRaises(TypeError, _FileIO, _testcapi.INT_MAX + 1)[](#l5.16)
self.assertRaises(TypeError, _FileIO, _testcapi.INT_MIN - 1)[](#l5.17)
def testBadModeArgument(self): # verify that we get a sensible error message for bad mode argument
--- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -32,6 +32,7 @@ import time import unittest import warnings import weakref +import _testcapi from collections import deque, UserList from itertools import cycle, count from test import support @@ -1970,6 +1971,14 @@ class TextIOWrapperTest(unittest.TestCas os.environ.clear() os.environ.update(old_environ)
Issue 15989
- def test_device_encoding(self):
b = self.BytesIO()[](#l6.17)
b.fileno = lambda: _testcapi.INT_MAX + 1[](#l6.18)
self.assertRaises(OverflowError, self.TextIOWrapper, b)[](#l6.19)
b.fileno = lambda: _testcapi.UINT_MAX + 1[](#l6.20)
self.assertRaises(OverflowError, self.TextIOWrapper, b)[](#l6.21)
+ def test_encoding(self): # Check the encoding attribute is always set, and valid b = self.BytesIO()
--- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py @@ -1,6 +1,7 @@
Test case for the os.poll() function
import os, select, random, unittest, subprocess +import _testcapi from test.support import TESTFN, run_unittest try: @@ -151,6 +152,15 @@ class PollTests(unittest.TestCase): if x != 5: self.fail('Overflow must have occurred')
pollster = select.poll()[](#l7.15)
# Issue 15989[](#l7.16)
self.assertRaises(OverflowError, pollster.register, 0,[](#l7.17)
_testcapi.SHRT_MAX + 1)[](#l7.18)
self.assertRaises(OverflowError, pollster.register, 0,[](#l7.19)
_testcapi.USHRT_MAX + 1)[](#l7.20)
self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1)[](#l7.21)
self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_MAX + 1)[](#l7.22)
+ def test_main(): run_unittest(PollTests)
--- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -17,6 +17,7 @@ import stat import tempfile import unittest import warnings +import _testcapi _DUMMY_SYMLINK = os.path.join(tempfile.gettempdir(), support.TESTFN + '-dummy-symlink') @@ -537,6 +538,10 @@ class PosixTester(unittest.TestCase): except OSError: pass
# Issue 15989[](#l8.15)
self.assertRaises(OverflowError, os.pipe2, _testcapi.INT_MAX + 1)[](#l8.16)
self.assertRaises(OverflowError, os.pipe2, _testcapi.UINT_MAX + 1)[](#l8.17)
+ def test_utime(self): if hasattr(posix, 'utime'): now = time.time()
--- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1262,11 +1262,17 @@ class GeneralModuleTests(unittest.TestCa for protocol in range(pickle.HIGHEST_PROTOCOL + 1): self.assertRaises(TypeError, pickle.dumps, sock, protocol)
- def test_listen_backlog(self):
for backlog in 0, -1:[](#l9.9)
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)[](#l9.10)
srv.bind((HOST, 0))[](#l9.11)
srv.listen(backlog)[](#l9.12)
srv.close()[](#l9.13)
# Issue 15989[](#l9.15) srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)[](#l9.16) srv.bind((HOST, 0))[](#l9.17)
# backlog = 0[](#l9.18)
srv.listen(0)[](#l9.19)
self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)[](#l9.20) srv.close()[](#l9.21)
@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @@ -1582,6 +1588,11 @@ class BasicTCPTest(SocketConnectedTest): def _testShutdown(self): self.serv_conn.send(MSG)
# Issue 15989[](#l9.28)
self.assertRaises(OverflowError, self.serv_conn.shutdown,[](#l9.29)
_testcapi.INT_MAX + 1)[](#l9.30)
self.assertRaises(OverflowError, self.serv_conn.shutdown,[](#l9.31)
2 + (_testcapi.UINT_MAX + 1))[](#l9.32) self.serv_conn.shutdown(2)[](#l9.33)
def testDetach(self): @@ -3563,6 +3574,11 @@ class NonBlockingTCPTests(ThreadedTCPSoc pass end = time.time() self.assertTrue((end - start) < 1.0, "Error setting non-blocking mode.")
# Issue 15989[](#l9.40)
self.assertRaises(OverflowError, self.serv.setblocking,[](#l9.41)
_testcapi.INT_MAX + 1)[](#l9.42)
self.assertRaises(OverflowError, self.serv.setblocking,[](#l9.43)
_testcapi.UINT_MAX + 1)[](#l9.44)
def _testSetBlocking(self): pass
--- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -335,7 +335,7 @@ PyCStructUnionType_update_stgdict(PyObje isPacked = PyObject_GetAttrString(type, "pack"); if (isPacked) {
pack = PyLong_AsLong(isPacked);[](#l10.7)
pack = _PyLong_AsInt(isPacked);[](#l10.8) if (pack < 0 || PyErr_Occurred()) {[](#l10.9) Py_XDECREF(isPacked);[](#l10.10) PyErr_SetString(PyExc_ValueError,[](#l10.11)
--- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -244,7 +244,7 @@ fileio_init(PyObject *oself, PyObject *a return -1; }
- fd = _PyLong_AsInt(nameobj); if (fd < 0) { if (!PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError,
@@ -382,7 +382,7 @@ fileio_init(PyObject *oself, PyObject *a goto error; }
self->fd = PyLong_AsLong(fdobj);[](#l11.16)
self->fd = _PyLong_AsInt(fdobj);[](#l11.17) Py_DECREF(fdobj);[](#l11.18) if (self->fd == -1) {[](#l11.19) goto error;[](#l11.20)
--- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -881,7 +881,7 @@ textiowrapper_init(textio *self, PyObjec } } else {
int fd = (int) PyLong_AsLong(fileno);[](#l12.7)
int fd = _PyLong_AsInt(fileno);[](#l12.8) Py_DECREF(fileno);[](#l12.9) if (fd == -1 && PyErr_Occurred()) {[](#l12.10) goto error;[](#l12.11)
--- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -725,7 +725,7 @@ build_node_children(PyObject tuple, nod / elem must always be a sequence, however simple / PyObject elem = PySequence_GetItem(tuple, i); int ok = elem != NULL;
long type = 0;[](#l13.7)
int type = 0;[](#l13.8) char *strn = 0;[](#l13.9)
if (ok) @@ -736,8 +736,14 @@ build_node_children(PyObject *tuple, nod ok = 0; else { ok = PyLong_Check(temp);
if (ok)[](#l13.16)
type = PyLong_AS_LONG(temp);[](#l13.17)
if (ok) {[](#l13.18)
type = _PyLong_AsInt(temp);[](#l13.19)
if (type == -1 && PyErr_Occurred()) {[](#l13.20)
Py_DECREF(temp);[](#l13.21)
Py_DECREF(elem);[](#l13.22)
return 0;[](#l13.23)
}[](#l13.24)
}[](#l13.25) Py_DECREF(temp);[](#l13.26) }[](#l13.27) }[](#l13.28)
@@ -773,8 +779,16 @@ build_node_children(PyObject *tuple, nod if (len == 3) { PyObject *o = PySequence_GetItem(elem, 2); if (o != NULL) {
if (PyLong_Check(o))[](#l13.33)
*line_num = PyLong_AS_LONG(o);[](#l13.34)
if (PyLong_Check(o)) {[](#l13.35)
int num = _PyLong_AsInt(o);[](#l13.36)
if (num == -1 && PyErr_Occurred()) {[](#l13.37)
Py_DECREF(o);[](#l13.38)
Py_DECREF(temp);[](#l13.39)
Py_DECREF(elem);[](#l13.40)
return 0;[](#l13.41)
}[](#l13.42)
*line_num = num;[](#l13.43)
}[](#l13.44) else {[](#l13.45) PyErr_Format(parser_error,[](#l13.46) "third item in terminal node must be an"[](#l13.47)
--- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7647,7 +7647,7 @@ posix_pipe2(PyObject *self, PyObject *ar int fds[2]; int res;
--- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -352,10 +352,13 @@ update_ufd_array(pollObject *self) i = pos = 0; while (PyDict_Next(self->dict, &pos, &key, &value)) {
self->ufds[i].fd = PyLong_AsLong(key);[](#l15.7)
assert(i < self->ufd_len);[](#l15.8)
/* Never overflow */[](#l15.9)
}self->ufds[i].fd = (int)PyLong_AsLong(key);[](#l15.10) self->ufds[i].events = (short)PyLong_AsLong(value);[](#l15.11) i++;[](#l15.12)
- assert(i == self->ufd_len); self->ufd_uptodate = 1; return 1; }
@@ -371,10 +374,11 @@ static PyObject * poll_register(pollObject *self, PyObject *args) { PyObject *o, *key, *value;
- if (!PyArg_ParseTuple(args, "O|h:register", &o, &events)) { return NULL; } @@ -513,7 +517,7 @@ poll_poll(pollObject *self, PyObject *ar tout = PyNumber_Long(tout); if (!tout) return NULL;
timeout = PyLong_AsLong(tout);[](#l15.36)
timeout = _PyLong_AsInt(tout);[](#l15.37) Py_DECREF(tout);[](#l15.38) if (timeout == -1 && PyErr_Occurred())[](#l15.39) return NULL;[](#l15.40)
--- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2013,7 +2013,7 @@ For IP sockets, the address info is a pa static PyObject * sock_setblocking(PySocketSockObject *s, PyObject *arg) {
block = PyLong_AsLong(arg); if (block == -1 && PyErr_Occurred()) @@ -2495,7 +2495,7 @@ sock_listen(PySocketSockObject *s, PyObj int backlog; int res;
- backlog = _PyLong_AsInt(arg); if (backlog == -1 && PyErr_Occurred()) return NULL; Py_BEGIN_ALLOW_THREADS @@ -3647,7 +3647,7 @@ sock_shutdown(PySocketSockObject *s, PyO int how; int res;
--- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -200,7 +200,7 @@ PyObject_AsFileDescriptor(PyObject *o) _Py_IDENTIFIER(fileno); if (PyLong_Check(o)) {
fd = PyLong_AsLong(o);[](#l17.7)
} else if ((meth = _PyObject_GetAttrId(o, &PyId_fileno)) != NULL) { @@ -210,7 +210,7 @@ PyObject_AsFileDescriptor(PyObject *o) return -1;fd = _PyLong_AsInt(o);[](#l17.8)
fd = PyLong_AsLong(fno);[](#l17.16)
fd = _PyLong_AsInt(fno);[](#l17.17) Py_DECREF(fno);[](#l17.18) }[](#l17.19) else {[](#l17.20)
--- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -434,6 +434,24 @@ PyLong_AsLong(PyObject obj) return result; } +/ Get a C int from a long int object or any object that has an int
+int +_PyLong_AsInt(PyObject *obj) +{
- int overflow;
- long result = PyLong_AsLongAndOverflow(obj, &overflow);
- if (overflow || result > INT_MAX || result < INT_MIN) {
/* XXX: could be cute and give a different[](#l18.16)
message for overflow == -1 */[](#l18.17)
PyErr_SetString(PyExc_OverflowError,[](#l18.18)
"Python int too large to convert to C int");[](#l18.19)
return -1;[](#l18.20)
- }
- return (int)result;
+} + /* Get a Py_ssize_t from a long int object. Returns -1 and sets an error condition if overflow occurs. */
--- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13521,7 +13521,7 @@ unicode_format_arg_parse(struct unicode_ "* wants int"); return -1; }
arg->width = PyLong_AsLong(v);[](#l19.7)
arg->width = PyLong_AsSsize_t(v);[](#l19.8) if (arg->width == -1 && PyErr_Occurred())[](#l19.9) return -1;[](#l19.10) if (arg->width < 0) {[](#l19.11)
@@ -13568,7 +13568,7 @@ unicode_format_arg_parse(struct unicode_ "* wants int"); return -1; }
arg->prec = PyLong_AsLong(v);[](#l19.16)
arg->prec = _PyLong_AsInt(v);[](#l19.17) if (arg->prec == -1 && PyErr_Occurred())[](#l19.18) return -1;[](#l19.19) if (arg->prec < 0)[](#l19.20)