8000 bpo-30061: Check if PyObject_Size()/PySequence_Size()/PyMapping_Size(… · python/cpython@680fea4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 680fea4

Browse files
bpo-30061: Check if PyObject_Size()/PySequence_Size()/PyMapping_Size() (#1096) (#1180)
raised an error. (cherry picked from commit bf623ae)
1 parent 8e5b52a commit 680fea4
Copy full SHA for 680fea4

File tree

7 files changed

+95
-31
lines changed

7 files changed

+95
-31
lines changed

Lib/test/test_io.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,22 @@ def test_readline(self):
543543
with self.open(support.TESTFN, "r") as f:
544544
self.assertRaises(TypeError, f.readline, 5.3)
545545

546+
def test_readline_nonsizeable(self):
547+
# Issue #30061
548+
# Crash when readline() returns an object without __len__
549+
class R(self.IOBase):
550+
def readline(self):
551+
return None
552+
self.assertRaises((TypeError, StopIteration), next, R())
553+
554+
def test_next_nonsizeable(self):
555+
# Issue #30061
556+
# Crash when __next__() returns an object without __len__
557+
class R(self.IOBase):
558+
def __next__(self):
559+
return None
560+
self.assertRaises(TypeError, R().readlines, 1)
561+
546562
def test_raw_bytes_io(self):
547563
f = self.BytesIO()
548564
self.write_ops(f)

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ Core and Builtins
3232
Library
3333
-------
3434

35+
- bpo-30061: Fixed crashes in IOBase methods __next__() and readlines() when
36+
readline() or __next__() respectively return non-sizeable object.
37+
Fixed possible other errors caused by not checking results of PyObject_Size(),
38+
PySequence_Size(), or PyMapping_Size().
39+
3540
- bpo-30017: Allowed calling the close() method of the zip entry writer object
3641
multiple times. Writing to a closed writer now always produces a ValueError.
3742

Modules/_io/iobase.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,8 @@ iobase_iternext(PyObject *self)
625625
if (line == NULL)
626626
return NULL;
627627

628-
if (PyObject_Size(line) == 0) {
628+
if (PyObject_Size(line) <= 0) {
629+
/* Error or empty */
629630
Py_DECREF(line);
630631
return NULL;
631632
}
@@ -676,6 +677,7 @@ _io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint)
676677
}
677678

678679
while (1) {
680+
Py_ssize_t line_length;
679681
PyObject *line = PyIter_Next(it);
680682
if (line == NULL) {
681683
if (PyErr_Occurred()) {
@@ -689,11 +691,14 @@ _io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint)
689691
Py_DECREF(line);
690692
goto error;
691693
}
692-
length += PyObject_Size(line);
694+
line_length = PyObject_Size(line);
693695
Py_DECREF(line);
694-
695-
if (length > hint)
696+
if (line_length < 0) {
697+
goto error;
698+
}
699+
if (line_length > hint - length)
696700
break;
701+
length += line_length;
697702
}
698703

699704
Py_DECREF(it);

Modules/_winapi.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -722,17 +722,22 @@ getenvironment(PyObject* environment)
722722
return NULL;
723723
}
724724

725-
envsize = PyMapping_Length(environment);
726-
727725
keys = PyMapping_Keys(environment);
728726
values = PyMapping_Values(environment);
729727
if (!keys || !values)
730728
goto error;
731729

730+
envsize = PySequence_Fast_GET_SIZE(keys);
731+
if (PySequence_Fast_GET_SIZE(values) != envsize) {
732+
PyErr_SetString(PyExc_RuntimeError,
733+
"environment changed size during iteration");
734+
goto error;
735+
}
736+
732737
totalsize = 1; /* trailing null character */
733738
for (i = 0; i < envsize; i++) {
734-
PyObject* key = PyList_GET_ITEM(keys, i);
735-
PyObject* value = PyList_GET_ITEM(values, i);
739+
PyObject* key = PySequence_Fast_GET_ITEM(keys, i);
740+
PyObject* value = PySequence_Fast_GET_ITEM(values, i);
736741

737742
if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
738743
PyErr_SetString(PyExc_TypeError,
@@ -760,8 +765,8 @@ getenvironment(PyObject* environment)
760765
end = buffer + totalsize;
761766

762767
for (i = 0; i < envsize; i++) {
763-
PyObject* key = PyList_GET_ITEM(keys, i);
764-
PyObject* value = PyList_GET_ITEM(values, i);
768+
PyObject* key = PySequence_Fast_GET_ITEM(keys, i);
769+
PyObject* value = PySequence_Fast_GET_ITEM(values, i);
765770
if (!PyUnicode_AsUCS4(key, p, end - p, 0))
766771
goto error;
767772
p += PyUnicode_GET_LENGTH(key);

Modules/cjkcodecs/multibytecodec.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,9 @@ _multibytecodec_MultibyteStreamWriter_writelines(MultibyteStreamWriterObject *se
16701670
if (r == -1)
16711671
return NULL;
16721672
}
1673+
/* PySequence_Length() can fail */
1674+
if (PyErr_Occurred())
1675+
return NULL;
16731676

16741677
Py_RETURN_NONE;
16751678
}

Modules/posixmodule.c

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6650,14 +6650,17 @@ static PyObject *
66506650
os_setgroups(PyObject *module, PyObject *groups)
66516651
/*[clinic end generated code: output=3fcb32aad58c5ecd input=fa742ca3daf85a7e]*/
66526652
{
6653-
int i, len;
6653+
Py_ssize_t i, len;
66546654
gid_t grouplist[MAX_GROUPS];
66556655

66566656
if (!PySequence_Check(groups)) {
66576657
PyErr_SetString(PyExc_TypeError, "setgroups argument must be a sequence");
66586658
return NULL;
66596659
}
66606660
len = PySequence_Size(groups);
6661+
if (len < 0) {
6662+
return NULL;
6663+
}
66616664
if (len > MAX_GROUPS) {
66626665
PyErr_SetString(PyExc_ValueError, "too many groups");
66636666
return NULL;
@@ -7886,9 +7889,9 @@ os_read_impl(PyObject *module, int fd, Py_ssize_t length)
78867889
#if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
78877890
|| defined(__APPLE__))) || defined(HAVE_READV) || defined(HAVE_WRITEV)
78887891
static Py_ssize_t
7889-
iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, int cnt, int type)
7892+
iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, Py_ssize_t cnt, int type)
78907893
{
7891-
int i, j;
7894+
Py_ssize_t i, j;
78927895
Py_ssize_t blen, total = 0;
78937896

78947897
*iov = PyMem_New(struct iovec, cnt);
@@ -7965,8 +7968,7 @@ static Py_ssize_t
79657968
os_readv_impl(PyObject *module, int fd, PyObject *buffers)
79667969
/*[clinic end generated code: output=792da062d3fcebdb input=e679eb5dbfa0357d]*/
79677970
{
7968-
int cnt;
7969-
Py_ssize_t n;
7971+
Py_ssize_t cnt, n;
79707972
int async_err = 0;
79717973
struct iovec *iov;
79727974
Py_buffer *buf;
@@ -7978,6 +7980,8 @@ os_readv_impl(PyObject *module, int fd, PyObject *buffers)
79787980
}
79797981

79807982
cnt = PySequence_Size(buffers);
7983+
if (cnt < 0)
7984+
return -1;
79817985

79827986
if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0)
79837987
return -1;
@@ -8116,15 +8120,24 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
81168120
"sendfile() headers must be a sequence");
81178121
return NULL;
81188122
} else {
8119-
Py_ssize_t i = 0; /* Avoid uninitialized warning */
8120-
sf.hdr_cnt = PySequence_Size(headers);
8121-
if (sf.hdr_cnt > 0 &&
8122-
(i = iov_setup(&(sf.headers), &hbuf,
8123-
headers, sf.hdr_cnt, PyBUF_SIMPLE)) < 0)
8123+
Py_ssize_t i = PySequence_Size(headers);
8124+
if (i < 0)
8125+
return NULL;
8126+
if (i > INT_MAX) {
8127+
PyErr_SetString(PyExc_OverflowError,
8128+
"sendfile() header is too large");
81248129
return NULL;
8130+
}
8131+
if (i > 0) {
8132+
sf.hdr_cnt = (int)i;
8133+
i = iov_setup(&(sf.headers), &hbuf,
8134+
headers, sf.hdr_cnt, PyBUF_SIMPLE);
8135+
if (i < 0)
8136+
return NULL;
81258137
#ifdef __APPLE__
8126-
sbytes += i;
8138+
sbytes += i;
81278139
#endif
8140+
}
81288141
}
81298142
}
81308143
if (trailers != NULL) {
@@ -8133,15 +8146,24 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
81338146
"sendfile() trailers must be a sequence");
81348147
return NULL;
81358148
} else {
8136-
Py_ssize_t i = 0; /* Avoid uninitialized warning */
8137-
sf.trl_cnt = PySequence_Size(trailers);
8138-
if (sf.trl_cnt > 0 &&
8139-
(i = iov_setup(&(sf.trailers), &tbuf,
8140-
trailers, sf.trl_cnt, PyBUF_SIMPLE)) < 0)
8149+
Py_ssize_t i = PySequence_Size(trailers);
8150+
if (i < 0)
8151+
return NULL;
8152+
if (i > INT_MAX) {
8153+
PyErr_SetString(PyExc_OverflowError,
8154+
"sendfile() trailer is too large");
81418155
return NULL;
8156+
}
8157+
if (i > 0) {
8158+
sf.trl_cnt = (int)i;
8159+
i = iov_setup(&(sf.trailers), &tbuf,
8160+
trailers, sf.trl_cnt, PyBUF_SIMPLE);
8161+
if (i < 0)
8162+
return NULL;
81428163
#ifdef __APPLE__
8143-
sbytes += i;
8164+
sbytes += i;
81448165
#endif
8166+
}
81458167
}
81468168
}
81478169

@@ -8411,7 +8433,7 @@ static Py_ssize_t
84118433
os_writev_impl(PyObject *module, int fd, PyObject *buffers)
84128434
/*[clinic end generated code: output=56565cfac3aac15b input=5b8d17fe4189d2fe]*/
84138435
{
8414-
int cnt;
8436+
Py_ssize_t cnt;
84158437
Py_ssize_t result;
84168438
int async_err = 0;
84178439
struct iovec *iov;
@@ -8423,6 +8445,8 @@ os_writev_impl(PyObject *module, int fd, PyObject *buffers)
84238445
return -1;
84248446
}
84258447
cnt = PySequence_Size(buffers);
8448+
if (cnt < 0)
8449+
return -1;
84268450

84278451
if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) {
84288452
return -1;

Objects/setobject.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,20 +1550,26 @@ set_difference(PySetObject *so, PyObject *other)
15501550
PyObject *key;
15511551
Py_hash_t hash;
15521552
setentry *entry;
1553-
Py_ssize_t pos = 0;
1553+
Py_ssize_t pos = 0, other_size;
15541554
int rv;
15551555

15561556
if (PySet_GET_SIZE(so) == 0) {
15571557
return set_copy(so);
15581558
}
15591559

1560-
if (!PyAnySet_Check(other) && !PyDict_CheckExact(other)) {
1560+
if (PyAnySet_Check(other)) {
1561+
other_size = PySet_GET_SIZE(other);
1562+
}
1563+
else if (PyDict_CheckExact(other)) {
1564+
other_size = PyDict_Size(other);
1565+
}
1566+
else {
15611567
return set_copy_and_difference(so, other);
15621568
}
15631569

15641570
/* If len(so) much more than len(other), it's more efficient to simply copy
15651571
* so and then iterate other looking for common elements. */
1566-
if ((PySet_GET_SIZE(so) >> 2) > PyObject_Size(other)) {
1572+
if ((PySet_GET_SIZE(so) >> 2) > other_size) {
15671573
return set_copy_and_difference(so, other);
15681574
}
15691575

0 commit comments

Comments
 (0)
0