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

Skip to content

Commit 9101e23

Browse files
Issue #15989: Fix several occurrences of integer overflow
when result of PyLong_AsLong() narrowed to int without checks. This is a backport of changesets 13e2e44db99d and 525407d89277.
2 parents bd8f290 + 441d30f commit 9101e23

19 files changed

Lines changed: 151 additions & 25 deletions

Include/longobject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *);
2626
PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *);
2727
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
2828
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
29+
#ifndef Py_LIMITED_API
30+
PyAPI_FUNC(int) _PyLong_AsInt(PyObject *);
31+
#endif
2932
PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
3033

3134
/* It may be useful in the future. I've added it in the PyInt -> PyLong

Lib/ctypes/test/test_structures.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22
from ctypes import *
33
from struct import calcsize
4+
import _testcapi
45

56
class SubclassesTest(unittest.TestCase):
67
def test_subclass(self):
@@ -199,6 +200,14 @@ class X(Structure):
199200
"_pack_": -1}
200201
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
201202

203+
# Issue 15989
204+
d = {"_fields_": [("a", c_byte)],
205+
"_pack_": _testcapi.INT_MAX + 1}
206+
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
207+
d = {"_fields_": [("a", c_byte)],
208+
"_pack_": _testcapi.UINT_MAX + 2}
209+
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
210+
202211
def test_initializers(self):
203212
class Person(Structure):
204213
_fields_ = [("name", c_char*6),

Lib/test/string_tests.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import unittest, string, sys, struct
66
from test import support
77
from collections import UserList
8+
import _testcapi
89

910
class Sequence:
1011
def __init__(self, seq='wxyz'): self.seq = seq
@@ -1206,6 +1207,16 @@ def test_formatting(self):
12061207
self.checkraises(ValueError, '%%%df' % (2**64), '__mod__', (3.2))
12071208
self.checkraises(ValueError, '%%.%df' % (2**64), '__mod__', (3.2))
12081209

1210+
self.checkraises(OverflowError, '%*s', '__mod__',
1211+
(_testcapi.PY_SSIZE_T_MAX + 1, ''))
1212+
self.checkraises(OverflowError, '%.*f', '__mod__',
1213+
(_testcapi.INT_MAX + 1, 1. / 7))
1214+
# Issue 15989
1215+
self.checkraises(OverflowError, '%*s', '__mod__',
1216+
(1 << (_testcapi.PY_SSIZE_T_MAX.bit_length() + 1), ''))
1217+
self.checkraises(OverflowError, '%.*f', '__mod__',
1218+
(_testcapi.UINT_MAX + 1, 1. / 7))
1219+
12091220
class X(object): pass
12101221
self.checkraises(TypeError, 'abc', '__mod__', X())
12111222

Lib/test/test_fcntl.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import struct
88
import sys
9+
import _testcapi
910
import unittest
1011
from test.support import verbose, TESTFN, unlink, run_unittest, import_module
1112

@@ -76,6 +77,26 @@ def test_fcntl_file_descriptor(self):
7677
rv = fcntl.fcntl(self.f, fcntl.F_SETLKW, lockdata)
7778
self.f.close()
7879

80+
def test_fcntl_bad_file(self):
81+
class F:
82+
def __init__(self, fn):
83+
self.fn = fn
84+
def fileno(self):
85+
return self.fn
86+
self.assertRaises(ValueError, fcntl.fcntl, -1, fcntl.F_SETFL, os.O_NONBLOCK)
87+
self.assertRaises(ValueError, fcntl.fcntl, F(-1), fcntl.F_SETFL, os.O_NONBLOCK)
88+
self.assertRaises(TypeError, fcntl.fcntl, 'spam', fcntl.F_SETFL, os.O_NONBLOCK)
89+
self.assertRaises(TypeError, fcntl.fcntl, F('spam'), fcntl.F_SETFL, os.O_NONBLOCK)
90+
# Issue 15989
91+
self.assertRaises(OverflowError, fcntl.fcntl, _testcapi.INT_MAX + 1,
92+
fcntl.F_SETFL, os.O_NONBLOCK)
93+
self.assertRaises(OverflowError, fcntl.fcntl, F(_testcapi.INT_MAX + 1),
94+
fcntl.F_SETFL, os.O_NONBLOCK)
95+
self.assertRaises(OverflowError, fcntl.fcntl, _testcapi.INT_MIN - 1,
96+
fcntl.F_SETFL, os.O_NONBLOCK)
97+
self.assertRaises(OverflowError, fcntl.fcntl, F(_testcapi.INT_MIN - 1),
98+
fcntl.F_SETFL, os.O_NONBLOCK)
99+
79100
def test_fcntl_64_bit(self):
80101
# Issue #1309352: fcntl shouldn't fail when the third arg fits in a
81102
# C 'long' but not in a C 'int'.

Lib/test/test_fileio.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from array import array
99
from weakref import proxy
1010
from functools import wraps
11+
import _testcapi
1112

1213
from test.support import TESTFN, check_warnings, run_unittest, make_bad_fd
1314
from collections import UserList
@@ -347,6 +348,9 @@ def testInvalidFd(self):
347348
if sys.platform == 'win32':
348349
import msvcrt
349350
self.assertRaises(IOError, msvcrt.get_osfhandle, make_bad_fd())
351+
# Issue 15989
352+
self.assertRaises(TypeError, _FileIO, _testcapi.INT_MAX + 1)
353+
self.assertRaises(TypeError, _FileIO, _testcapi.INT_MIN - 1)
350354

351355
def testBadModeArgument(self):
352356
# verify that we get a sensible error message for bad mode argument

Lib/test/test_io.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import unittest
3333
import warnings
3434
import weakref
35+
import _testcapi
3536
from collections import deque, UserList
3637
from itertools import cycle, count
3738
from test import support
@@ -1962,6 +1963,14 @@ def test_default_encoding(self):
19621963
os.environ.clear()
19631964
os.environ.update(old_environ)
19641965

1966+
# Issue 15989
1967+
def test_device_encoding(self):
1968+
b = self.BytesIO()
1969+
b.fileno = lambda: _testcapi.INT_MAX + 1
1970+
self.assertRaises(OverflowError, self.TextIOWrapper, b)
1971+
b.fileno = lambda: _testcapi.UINT_MAX + 1
1972+
self.assertRaises(OverflowError, self.TextIOWrapper, b)
1973+
19651974
def test_encoding(self):
19661975
# Check the encoding attribute is always set, and valid
19671976
b = self.BytesIO()

Lib/test/test_poll.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Test case for the os.poll() function
22

33
import os, select, random, unittest
4+
import _testcapi
45
from test.support import TESTFN, run_unittest
56

67
try:
@@ -150,6 +151,15 @@ def test_poll3(self):
150151
if x != 5:
151152
self.fail('Overflow must have occurred')
152153

154+
pollster = select.poll()
155+
# Issue 15989
156+
self.assertRaises(OverflowError, pollster.register, 0,
157+
_testcapi.SHRT_MAX + 1)
158+
self.assertRaises(OverflowError, pollster.register, 0,
159+
_testcapi.USHRT_MAX + 1)
160+
self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1)
161+
self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_MAX + 1)
162+
153163
def test_main():
154164
run_unittest(PollTests)
155165

Lib/test/test_posix.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import tempfile
1818
import unittest
1919
import warnings
20+
import _testcapi
2021

2122
_DUMMY_SYMLINK = os.path.join(tempfile.gettempdir(),
2223
support.TESTFN + '-dummy-symlink')
@@ -537,6 +538,10 @@ def test_pipe2(self):
537538
except OSError:
538539
pass
539540

541+
# Issue 15989
542+
self.assertRaises(OverflowError, os.pipe2, _testcapi.INT_MAX + 1)
543+
self.assertRaises(OverflowError, os.pipe2, _testcapi.UINT_MAX + 1)
544+
540545
def test_utime(self):
541546
if hasattr(posix, 'utime'):
542547
now = time.time()

Lib/test/test_socket.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,11 +1262,17 @@ def test_pickle(self):
12621262
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
12631263
self.assertRaises(TypeError, pickle.dumps, sock, protocol)
12641264

1265-
def test_listen_backlog0(self):
1265+
def test_listen_backlog(self):
1266+
for backlog in 0, -1:
1267+
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1268+
srv.bind((HOST, 0))
1269+
srv.listen(backlog)
1270+
srv.close()
1271+
1272+
# Issue 15989
12661273
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12671274
srv.bind((HOST, 0))
1268-
# backlog = 0
1269-
srv.listen(0)
1275+
self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)
12701276
srv.close()
12711277

12721278
@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
@@ -1582,6 +1588,11 @@ def testShutdown(self):
15821588

15831589
def _testShutdown(self):
15841590
self.serv_conn.send(MSG)
1591+
# Issue 15989
1592+
self.assertRaises(OverflowError, self.serv_conn.shutdown,
1593+
_testcapi.INT_MAX + 1)
1594+
self.assertRaises(OverflowError, self.serv_conn.shutdown,
1595+
2 + (_testcapi.UINT_MAX + 1))
15851596
self.serv_conn.shutdown(2)
15861597

15871598
def testDetach(self):
@@ -3555,14 +3566,21 @@ def __init__(self, methodName='runTest'):
35553566

35563567
def testSetBlocking(self):
35573568
# Testing whether set blocking works
3558-
self.serv.setblocking(0)
3569+
self.serv.setblocking(True)
3570+
self.assertIsNone(self.serv.gettimeout())
3571+
self.serv.setblocking(False)
3572+
self.assertEqual(self.serv.gettimeout(), 0.0)
35593573
start = time.time()
35603574
try:
35613575
self.serv.accept()
35623576
except socket.error:
35633577
pass
35643578
end = time.time()
35653579
self.assertTrue((end - start) < 1.0, "Error setting non-blocking mode.")
3580+
# Issue 15989
3581+
if _testcapi.UINT_MAX < _testcapi.ULONG_MAX:
3582+
self.serv.setblocking(_testcapi.UINT_MAX + 1)
3583+
self.assertIsNone(self.serv.gettimeout())
35663584

35673585
def _testSetBlocking(self):
35683586
pass

Modules/_ctypes/stgdict.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
335335

336336
isPacked = PyObject_GetAttrString(type, "_pack_");
337337
if (isPacked) {
338-
pack = PyLong_AsLong(isPacked);
338+
pack = _PyLong_AsInt(isPacked);
339339
if (pack < 0 || PyErr_Occurred()) {
340340
Py_XDECREF(isPacked);
341341
PyErr_SetString(PyExc_ValueError,

0 commit comments

Comments
 (0)