cpython: d544873d62e9 (original) (raw)
Mercurial > cpython
changeset 81590:d544873d62e9 2.7
Issue #15989: Fix several occurrences of integer overflow when result of PyInt_AsLong() or PyLong_AsLong() narrowed to int without checks. This is a backport of changesets 13e2e44db99d and 525407d89277. [#15989]
line wrap: on
line diff
--- a/Include/intobject.h +++ b/Include/intobject.h @@ -40,6 +40,7 @@ PyAPI_FUNC(PyObject *) PyInt_FromSize_t( PyAPI_FUNC(PyObject *) PyInt_FromSsize_t(Py_ssize_t); PyAPI_FUNC(long) PyInt_AsLong(PyObject *); PyAPI_FUNC(Py_ssize_t) PyInt_AsSsize_t(PyObject *); +PyAPI_FUNC(int) _PyInt_AsInt(PyObject *); PyAPI_FUNC(unsigned long) PyInt_AsUnsignedLongMask(PyObject *); #ifdef HAVE_LONG_LONG PyAPI_FUNC(unsigned PY_LONG_LONG) PyInt_AsUnsignedLongLongMask(PyObject *);
--- a/Include/longobject.h +++ b/Include/longobject.h @@ -25,6 +25,7 @@ PyAPI_FUNC(long) PyLong_AsLongAndOverflo PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *); +PyAPI_FUNC(int) _PyLong_AsInt(PyObject *); PyAPI_FUNC(PyObject ) PyLong_GetInfo(void); / For use by intobject.c only */
--- 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[](#l3.15)
d = {"_fields_": [("a", c_byte)],[](#l3.16)
"_pack_": _testcapi.INT_MAX + 1}[](#l3.17)
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)[](#l3.18)
d = {"_fields_": [("a", c_byte)],[](#l3.19)
"_pack_": _testcapi.UINT_MAX + 2}[](#l3.20)
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)[](#l3.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 test_support from UserList import UserList +import _testcapi class Sequence: def init(self, seq='wxyz'): self.seq = seq @@ -1113,6 +1114,20 @@ class MixinStrUnicodeUserStringTest: self.checkraises(TypeError, '%10.*f', 'mod', ('foo', 42.)) self.checkraises(ValueError, '%10', 'mod', (42,))
if _testcapi.PY_SSIZE_T_MAX < sys.maxint:[](#l4.15)
self.checkraises(OverflowError, '%*s', '__mod__',[](#l4.16)
(_testcapi.PY_SSIZE_T_MAX + 1, ''))[](#l4.17)
if _testcapi.INT_MAX < sys.maxint:[](#l4.18)
self.checkraises(OverflowError, '%.*f', '__mod__',[](#l4.19)
(_testcapi.INT_MAX + 1, 1. / 7))[](#l4.20)
# Issue 15989[](#l4.21)
if 1 << (_testcapi.PY_SSIZE_T_MAX.bit_length() + 1) <= sys.maxint:[](#l4.22)
self.checkraises(OverflowError, '%*s', '__mod__',[](#l4.23)
(1 << (_testcapi.PY_SSIZE_T_MAX.bit_length() + 1), ''))[](#l4.24)
if _testcapi.UINT_MAX < sys.maxint:[](#l4.25)
self.checkraises(OverflowError, '%.*f', '__mod__',[](#l4.26)
(_testcapi.UINT_MAX + 1, 1. / 7))[](#l4.27)
+ class X(object): pass self.checkraises(TypeError, 'abc', 'mod', X())
--- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -6,6 +6,7 @@ OS/2+EMX doesn't support the file lockin import os import struct import sys +import _testcapi import unittest from test.test_support import (verbose, TESTFN, unlink, run_unittest, import_module) @@ -81,6 +82,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:[](#l5.16)
def __init__(self, fn):[](#l5.17)
self.fn = fn[](#l5.18)
def fileno(self):[](#l5.19)
return self.fn[](#l5.20)
self.assertRaises(ValueError, fcntl.fcntl, -1, fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.21)
self.assertRaises(ValueError, fcntl.fcntl, F(-1), fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.22)
self.assertRaises(TypeError, fcntl.fcntl, 'spam', fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.23)
self.assertRaises(TypeError, fcntl.fcntl, F('spam'), fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.24)
# Issue 15989[](#l5.25)
self.assertRaises(ValueError, fcntl.fcntl, _testcapi.INT_MAX + 1,[](#l5.26)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.27)
self.assertRaises(ValueError, fcntl.fcntl, F(_testcapi.INT_MAX + 1),[](#l5.28)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.29)
self.assertRaises(ValueError, fcntl.fcntl, _testcapi.INT_MIN - 1,[](#l5.30)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.31)
self.assertRaises(ValueError, fcntl.fcntl, F(_testcapi.INT_MIN - 1),[](#l5.32)
fcntl.F_SETFL, os.O_NONBLOCK)[](#l5.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 @@ -10,6 +10,7 @@ from array import array from weakref import proxy from functools import wraps from UserList import UserList +import _testcapi from test.test_support import TESTFN, check_warnings, run_unittest, make_bad_fd from test.test_support import py3k_bytes as bytes @@ -343,6 +344,9 @@ class OtherFileTests(unittest.TestCase): if sys.platform == 'win32': import msvcrt self.assertRaises(IOError, msvcrt.get_osfhandle, make_bad_fd())
# Issue 15989[](#l6.15)
self.assertRaises(TypeError, _FileIO, _testcapi.INT_MAX + 1)[](#l6.16)
self.assertRaises(TypeError, _FileIO, _testcapi.INT_MIN - 1)[](#l6.17)
def testBadModeArgument(self): # verify that we get a sensible error message for bad mode argument
--- 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 +import _testcapi from test.test_support import TESTFN, run_unittest try: @@ -150,6 +151,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_socket.py +++ b/Lib/test/test_socket.py @@ -6,6 +6,7 @@ from test import test_support import errno import socket import select +import _testcapi import time import traceback import Queue @@ -700,11 +701,17 @@ class GeneralModuleTests(unittest.TestCa def test_sendall_interrupted_with_timeout(self): self.check_sendall_interrupted(True)
- def test_listen_backlog(self):
for backlog in 0, -1:[](#l8.17)
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)[](#l8.18)
srv.bind((HOST, 0))[](#l8.19)
srv.listen(backlog)[](#l8.20)
srv.close()[](#l8.21)
# Issue 15989[](#l8.23) srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)[](#l8.24) srv.bind((HOST, 0))[](#l8.25)
# backlog = 0[](#l8.26)
srv.listen(0)[](#l8.27)
self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)[](#l8.28) srv.close()[](#l8.29)
@unittest.skipUnless(SUPPORTS_IPV6, 'IPv6 required for this test.') @@ -808,6 +815,11 @@ class BasicTCPTest(SocketConnectedTest): def _testShutdown(self): self.serv_conn.send(MSG)
# Issue 15989[](#l8.36)
self.assertRaises(OverflowError, self.serv_conn.shutdown,[](#l8.37)
_testcapi.INT_MAX + 1)[](#l8.38)
self.assertRaises(OverflowError, self.serv_conn.shutdown,[](#l8.39)
2 + (_testcapi.UINT_MAX + 1))[](#l8.40) self.serv_conn.shutdown(2)[](#l8.41)
@unittest.skipUnless(thread, 'Threading required for this test.') @@ -883,7 +895,10 @@ class NonBlockingTCPTests(ThreadedTCPSoc def testSetBlocking(self): # Testing whether set blocking works
self.serv.setblocking(0)[](#l8.48)
self.serv.setblocking(True)[](#l8.49)
self.assertIsNone(self.serv.gettimeout())[](#l8.50)
self.serv.setblocking(False)[](#l8.51)
self.assertEqual(self.serv.gettimeout(), 0.0)[](#l8.52) start = time.time()[](#l8.53) try:[](#l8.54) self.serv.accept()[](#l8.55)
@@ -891,6 +906,10 @@ class NonBlockingTCPTests(ThreadedTCPSoc pass end = time.time() self.assertTrue((end - start) < 1.0, "Error setting non-blocking mode.")
# Issue 15989[](#l8.60)
if _testcapi.UINT_MAX < _testcapi.ULONG_MAX:[](#l8.61)
self.serv.setblocking(_testcapi.UINT_MAX + 1)[](#l8.62)
self.assertIsNone(self.serv.gettimeout())[](#l8.63)
def _testSetBlocking(self): pass
--- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -343,7 +343,7 @@ PyCStructUnionType_update_stgdict(PyObje isPacked = PyObject_GetAttrString(type, "pack"); if (isPacked) {
pack = PyInt_AsLong(isPacked);[](#l9.7)
pack = _PyInt_AsInt(isPacked);[](#l9.8) if (pack < 0 || PyErr_Occurred()) {[](#l9.9) Py_XDECREF(isPacked);[](#l9.10) PyErr_SetString(PyExc_ValueError,[](#l9.11)
--- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -300,7 +300,8 @@ io_open(PyObject *self, PyObject *args, int text = 0, binary = 0, universal = 0; char rawmode[5], *m;
PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL; @@ -443,12 +444,12 @@ io_open(PyObject *self, PyObject *args, #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE { struct stat st;
long fileno;[](#l10.17)
int fileno;[](#l10.18) PyObject *res = PyObject_CallMethod(raw, "fileno", NULL);[](#l10.19) if (res == NULL)[](#l10.20) goto error;[](#l10.21)
fileno = PyInt_AsLong(res);[](#l10.23)
fileno = _PyInt_AsInt(res);[](#l10.24) Py_DECREF(res);[](#l10.25) if (fileno == -1 && PyErr_Occurred())[](#l10.26) goto error;[](#l10.27)
--- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -211,7 +211,7 @@ fileio_init(PyObject *oself, PyObject *a return -1; }
- fd = _PyLong_AsInt(nameobj); if (fd < 0) { if (!PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError,
--- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -343,10 +343,13 @@ update_ufd_array(pollObject *self) i = pos = 0; while (PyDict_Next(self->dict, &pos, &key, &value)) {
self->ufds[i].fd = PyInt_AsLong(key);[](#l12.7)
assert(i < self->ufd_len);[](#l12.8)
/* Never overflow */[](#l12.9)
}self->ufds[i].fd = (int)PyInt_AsLong(key);[](#l12.10) self->ufds[i].events = (short)PyInt_AsLong(value);[](#l12.11) i++;[](#l12.12)
- assert(i == self->ufd_len); self->ufd_uptodate = 1; return 1; }
@@ -362,10 +365,11 @@ static PyObject * poll_register(pollObject *self, PyObject *args) { PyObject *o, *key, *value;
- if (!PyArg_ParseTuple(args, "O|h:register", &o, &events)) { return NULL; } @@ -503,7 +507,7 @@ poll_poll(pollObject *self, PyObject *ar tout = PyNumber_Int(tout); if (!tout) return NULL;
timeout = PyInt_AsLong(tout);[](#l12.36)
timeout = _PyInt_AsInt(tout);[](#l12.37) Py_DECREF(tout);[](#l12.38) if (timeout == -1 && PyErr_Occurred())[](#l12.39) return NULL;[](#l12.40)
--- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1713,7 +1713,7 @@ info is a pair (hostaddr, port)."); static PyObject * sock_setblocking(PySocketSockObject *s, PyObject *arg) {
block = PyInt_AsLong(arg); if (block == -1 && PyErr_Occurred()) @@ -2243,7 +2243,7 @@ sock_listen(PySocketSockObject *s, PyObj int backlog; int res;
- backlog = _PyInt_AsInt(arg); if (backlog == -1 && PyErr_Occurred()) return NULL; Py_BEGIN_ALLOW_THREADS @@ -2894,7 +2894,7 @@ sock_shutdown(PySocketSockObject *s, PyO int how; int res;
--- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -2659,10 +2659,10 @@ int PyObject_AsFileDescriptor(PyObject * PyObject *meth; if (PyInt_Check(o)) {
fd = PyInt_AsLong(o);[](#l14.7)
fd = PyLong_AsLong(o);[](#l14.11)
} else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL) { @@ -2672,11 +2672,11 @@ int PyObject_AsFileDescriptor(PyObject * return -1;fd = _PyLong_AsInt(o);[](#l14.12)
fd = PyInt_AsLong(fno);[](#l14.20)
fd = _PyInt_AsInt(fno);[](#l14.21) Py_DECREF(fno);[](#l14.22) }[](#l14.23) else if (PyLong_Check(fno)) {[](#l14.24)
fd = PyLong_AsLong(fno);[](#l14.25)
fd = _PyLong_AsInt(fno);[](#l14.26) Py_DECREF(fno);[](#l14.27) }[](#l14.28) else {[](#l14.29)
--- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -189,6 +189,20 @@ PyInt_AsLong(register PyObject *op) return val; } +int +_PyInt_AsInt(PyObject *obj) +{
- long result = PyInt_AsLong(obj);
- if (result == -1 && PyErr_Occurred())
return -1;[](#l15.12)
- if (result > INT_MAX || result < INT_MIN) {
PyErr_SetString(PyExc_OverflowError,[](#l15.14)
"Python int too large to convert to C int");[](#l15.15)
return -1;[](#l15.16)
- }
- return (int)result;
+} + Py_ssize_t PyInt_AsSsize_t(register PyObject *op) {
--- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -339,6 +339,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[](#l16.16)
message for overflow == -1 */[](#l16.17)
PyErr_SetString(PyExc_OverflowError,[](#l16.18)
"Python int too large to convert to C int");[](#l16.19)
return -1;[](#l16.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 @@ -8411,7 +8411,9 @@ PyObject *PyUnicode_Format(PyObject for " wants int"); goto onError; }
width = PyInt_AsLong(v);[](#l17.7)
width = PyInt_AsSsize_t(v);[](#l17.8)
if (width == -1 && PyErr_Occurred())[](#l17.9)
goto onError;[](#l17.10) if (width < 0) {[](#l17.11) flags |= F_LJUST;[](#l17.12) width = -width;[](#l17.13)
@@ -8446,7 +8448,9 @@ PyObject *PyUnicode_Format(PyObject for " wants int"); goto onError; }
prec = PyInt_AsLong(v);[](#l17.18)
prec = _PyInt_AsInt(v);[](#l17.19)
if (prec == -1 && PyErr_Occurred())[](#l17.20)
goto onError;[](#l17.21) if (prec < 0)[](#l17.22) prec = 0;[](#l17.23) if (--fmtcnt >= 0)[](#l17.24)