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

Skip to content

Commit 441d30f

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.
1 parent ff12fae commit 441d30f

16 files changed

Lines changed: 129 additions & 20 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
@@ -1142,6 +1143,16 @@ def test_formatting(self):
11421143
self.checkraises(TypeError, '%10.*f', '__mod__', ('foo', 42.))
11431144
self.checkraises(ValueError, '%10', '__mod__', (42,))
11441145

1146+
self.checkraises(OverflowError, '%*s', '__mod__',
1147+
(_testcapi.PY_SSIZE_T_MAX + 1, ''))
1148+
self.checkraises(OverflowError, '%.*f', '__mod__',
1149+
(_testcapi.INT_MAX + 1, 1. / 7))
1150+
# Issue 15989
1151+
self.checkraises(OverflowError, '%*s', '__mod__',
1152+
(1 << (_testcapi.PY_SSIZE_T_MAX.bit_length() + 1), ''))
1153+
self.checkraises(OverflowError, '%.*f', '__mod__',
1154+
(_testcapi.UINT_MAX + 1, 1. / 7))
1155+
11451156
class X(object): pass
11461157
self.checkraises(TypeError, 'abc', '__mod__', X())
11471158

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
@@ -7,6 +7,7 @@
77
from array import array
88
from weakref import proxy
99
from functools import wraps
10+
import _testcapi
1011

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

350354
def testBadModeArgument(self):
351355
# 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
@@ -31,6 +31,7 @@
3131
import errno
3232
import warnings
3333
import pickle
34+
import _testcapi
3435
from itertools import cycle, count
3536
from collections import deque, UserList
3637
from test import support
@@ -1903,6 +1904,14 @@ def test_line_buffering(self):
19031904
t.write("A\rB")
19041905
self.assertEqual(r.getvalue(), b"XY\nZA\rB")
19051906

1907+
# Issue 15989
1908+
def test_device_encoding(self):
1909+
b = self.BytesIO()
1910+
b.fileno = lambda: _testcapi.INT_MAX + 1
1911+
self.assertRaises(OverflowError, self.TextIOWrapper, b)
1912+
b.fileno = lambda: _testcapi.UINT_MAX + 1
1913+
self.assertRaises(OverflowError, self.TextIOWrapper, b)
1914+
19061915
def test_encoding(self):
19071916
# Check the encoding attribute is always set, and valid
19081917
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_socket.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io
88
import socket
99
import select
10+
import _testcapi
1011
import time
1112
import traceback
1213
import queue
@@ -850,11 +851,17 @@ def test_unusable_closed_socketio(self):
850851
self.assertRaises(ValueError, fp.writable)
851852
self.assertRaises(ValueError, fp.seekable)
852853

853-
def testListenBacklog0(self):
854+
def test_listen_backlog(self):
855+
for backlog in 0, -1:
856+
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
857+
srv.bind((HOST, 0))
858+
srv.listen(backlog)
859+
srv.close()
860+
861+
# Issue 15989
854862
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
855863
srv.bind((HOST, 0))
856-
# backlog = 0
857-
srv.listen(0)
864+
self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)
858865
srv.close()
859866

860867
@unittest.skipUnless(SUPPORTS_IPV6, 'IPv6 required for this test.')
@@ -954,6 +961,11 @@ def testShutdown(self):
954961

955962
def _testShutdown(self):
956963
self.serv_conn.send(MSG)
964+
# Issue 15989
965+
self.assertRaises(OverflowError, self.serv_conn.shutdown,
966+
_testcapi.INT_MAX + 1)
967+
self.assertRaises(OverflowError, self.serv_conn.shutdown,
968+
2 + (_testcapi.UINT_MAX + 1))
957969
self.serv_conn.shutdown(2)
958970

959971
def testDetach(self):
@@ -1067,14 +1079,21 @@ def __init__(self, methodName='runTest'):
10671079

10681080
def testSetBlocking(self):
10691081
# Testing whether set blocking works
1070-
self.serv.setblocking(0)
1082+
self.serv.setblocking(True)
1083+
self.assertIsNone(self.serv.gettimeout())
1084+
self.serv.setblocking(False)
1085+
self.assertEqual(self.serv.gettimeout(), 0.0)
10711086
start = time.time()
10721087
try:
10731088
self.serv.accept()
10741089
except socket.error:
10751090
pass
10761091
end = time.time()
10771092
self.assertTrue((end - start) < 1.0, "Error setting non-blocking mode.")
1093+
# Issue 15989
1094+
if _testcapi.UINT_MAX < _testcapi.ULONG_MAX:
1095+
self.serv.setblocking(_testcapi.UINT_MAX + 1)
1096+
self.assertIsNone(self.serv.gettimeout())
10781097

10791098
def _testSetBlocking(self):
10801099
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,

Modules/_io/_iomodule.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
303303
int text = 0, binary = 0, universal = 0;
304304

305305
char rawmode[5], *m;
306-
int line_buffering, isatty;
306+
int line_buffering;
307+
long isatty;
307308

308309
PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL;
309310

@@ -441,12 +442,12 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
441442
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
442443
{
443444
struct stat st;
444-
long fileno;
445+
int fileno;
445446
PyObject *res = PyObject_CallMethod(raw, "fileno", NULL);
446447
if (res == NULL)
447448
goto error;
448449

449-
fileno = PyLong_AsLong(res);
450+
fileno = _PyLong_AsInt(res);
450451
Py_DECREF(res);
451452
if (fileno == -1 && PyErr_Occurred())
452453
goto error;

0 commit comments

Comments
 (0)