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

Skip to content

Commit e63af29

Browse files
[3.5] bpo-30061: Check if PyObject_Size()/PySequence_Size()/PyMapping_Size() (GH-1096) (GH-1180) (#1182)
raised an error. (cherry picked from commit bf623ae) (cherry picked from commit 680fea4)
1 parent 49a9059 commit e63af29
Copy full SHA for e63af29

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
@@ -536,6 +536,22 @@ def test_readline(self):
536536
with self.open(support.TESTFN, "r") as f:
537537
self.assertRaises(TypeError, f.readline, 5.3)
538538

539+
def test_readline_nonsizeable(self):
540+
# Issue #30061
541+
# Crash when readline() returns an object without __len__
542+
class R(self.IOBase):
543+
def readline(self):
544+
return None
545+
self.assertRaises((TypeError, StopIteration), next, R())
546+
547+
def test_next_nonsizeable(self):
548+
# Issue #30061
549+
# Crash when __next__() returns an object without __len__
550+
class R(self.IOBase):
551+
def __next__(self):
552+
return None
553+
self.assertRaises(TypeError, R().readlines, 1)
554+
539555
def test_raw_bytes_io(self):
540556
f = self.BytesIO()
541557
self.write_ops(f)

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ Extension Modules
4949
Library
5050
-------
5151

52+
- bpo-30061: Fixed crashes in IOBase methods __next__() and readlines() when
53+
readline() or __next__() respectively return non-sizeable object.
54+
Fixed possible other errors caused by not checking results of PyObject_Size(),
55+
PySequence_Size(), or PyMapping_Size().
56+
5257
- bpo-30068: _io._IOBase.readlines will check if it's closed first when
5358
hint is present.
5459

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
@@ -6755,14 +6755,17 @@ static PyObject *
67556755
os_setgroups(PyObject *module, PyObject *groups)
67566756
/*[clinic end generated code: output=3fcb32aad58c5ecd input=fa742ca3daf85a7e]*/
67576757
{
6758-
int i, len;
6758+
Py_ssize_t i, len;
67596759
gid_t grouplist[MAX_GROUPS];
67606760

67616761
if (!PySequence_Check(groups)) {
67626762
PyErr_SetString(PyExc_TypeError, "setgroups argument must be a sequence");
67636763
return NULL;
67646764
}
67656765
len = PySequence_Size(groups);
6766+
if (len < 0) {
6767+
return NULL;
6768+
}
67666769
if (len > MAX_GROUPS) {
67676770
PyErr_SetString(PyExc_ValueError, "too many groups");
67686771
return NULL;
@@ -8076,9 +8079,9 @@ os_read_impl(PyObject *module, int fd, Py_ssize_t length)
80768079
#if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
80778080
|| defined(__APPLE__))) || defined(HAVE_READV) || defined(HAVE_WRITEV)
80788081
static Py_ssize_t
8079-
iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, int cnt, int type)
8082+
iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, Py_ssize_t cnt, int type)
80808083
{
8081-
int i, j;
8084+
Py_ssize_t i, j;
80828085
Py_ssize_t blen, total = 0;
80838086

80848087
*iov = PyMem_New(struct iovec, cnt);
@@ -8155,8 +8158,7 @@ static Py_ssize_t
81558158
os_readv_impl(PyObject *module, int fd, PyObject *buffers)
81568159
/*[clinic end generated code: output=792da062d3fcebdb input=e679eb5dbfa0357d]*/
81578160
{
8158-
int cnt;
8159-
Py_ssize_t n;
8161+
Py_ssize_t cnt, n;
81608162
int async_err = 0;
81618163
struct iovec *iov;
81628164
Py_buffer *buf;
@@ -8168,6 +8170,8 @@ os_readv_impl(PyObject *module, int fd, PyObject *buffers)
81688170
}
81698171

81708172
cnt = PySequence_Size(buffers);
8173+
if (cnt < 0)
8174+
return -1;
81718175

81728176
if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0)
81738177
return -1;
@@ -8310,15 +8314,24 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
83108314
"sendfile() headers must be a sequence");
83118315
return NULL;
83128316
} else {
8313-
Py_ssize_t i = 0; /* Avoid uninitialized warning */
8314-
sf.hdr_cnt = PySequence_Size(headers);
8315-
if (sf.hdr_cnt > 0 &&
8316-
(i = iov_setup(&(sf.headers), &hbuf,
8317-
headers, sf.hdr_cnt, PyBUF_SIMPLE)) < 0)
8317+
Py_ssize_t i = PySequence_Size(headers);
8318+
if (i < 0)
8319+
return NULL;
8320+
if (i > INT_MAX) {
8321+
PyErr_SetString(PyExc_OverflowError,
8322+
"sendfile() header is too large");
83188323
return NULL;
8324+
}
8325+
if (i > 0) {
8326+
sf.hdr_cnt = (int)i;
8327+
i = iov_setup(&(sf.headers), &hbuf,
8328+
headers, sf.hdr_cnt, PyBUF_SIMPLE);
8329+
if (i < 0)
8330+
return NULL;
83198331
#ifdef __APPLE__
8320-
sbytes += i;
8332+
sbytes += i;
83218333
#endif
8334+
}
83228335
}
83238336
}
83248337
if (trailers != NULL) {
@@ -8327,15 +8340,24 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
83278340
"sendfile() trailers must be a sequence");
83288341
return NULL;
83298342
} else {
8330-
Py_ssize_t i = 0; /* Avoid uninitialized warning */
8331-
sf.trl_cnt = PySequence_Size(trailers);
8332-
if (sf.trl_cnt > 0 &&
8333-
(i = iov_setup(&(sf.trailers), &tbuf,
8334-
trailers, sf.trl_cnt, PyBUF_SIMPLE)) < 0)
8343+
Py_ssize_t i = PySequence_Size(trailers);
8344+
if (i < 0)
8345+
return NULL;
8346+
if (i > INT_MAX) {
8347+
PyErr_SetString(PyExc_OverflowError,
8348+
"sendfile() trailer is too large");
83358349
return NULL;
8350+
}
8351+
if (i > 0) {
8352+
sf.trl_cnt = (int)i;
8353+
i = iov_setup(&(sf.trailers), &tbuf,
8354+
trailers, sf.trl_cnt, PyBUF_SIMPLE);
8355+
if (i < 0)
8356+
return NULL;
83368357
#ifdef __APPLE__
8337-
sbytes += i;
8358+
sbytes += i;
83388359
#endif
8360+
}
83398361
}
83408362
}
83418363

@@ -8605,7 +8627,7 @@ static Py_ssize_t
86058627
os_writev_impl(PyObject *module, int fd, PyObject *buffers)
86068628
/*[clinic end generated code: output=56565cfac3aac15b input=5b8d17fe4189d2fe]*/
86078629
{
8608-
int cnt;
8630+
Py_ssize_t cnt;
86098631
Py_ssize_t result;
86108632
int async_err = 0;
86118633
struct iovec *iov;
@@ -8617,6 +8639,8 @@ os_writev_impl(PyObject *module, int fd, PyObject *buffers)
86178639
return -1;
86188640
}
86198641
cnt = PySequence_Size(buffers);
8642+
if (cnt < 0)
8643+
return -1;
86208644

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

Objects/setobject.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,15 +1498,21 @@ set_difference(PySetObject *so, PyObject *other)
14981498
{
14991499
PyObject *result;
15001500
setentry *entry;
1501-
Py_ssize_t pos = 0;
1501+
Py_ssize_t pos = 0, other_size;
15021502

1503-
if (!PyAnySet_Check(other) && !PyDict_CheckExact(other)) {
1503+
if (PyAnySet_Check(other)) {
1504+
other_size = PySet_GET_SIZE(other);
1505+
}
1506+
else if (PyDict_CheckExact(other)) {
1507+
other_size = PyDict_Size(other);
1508+
}
1509+
else {
15041510
return set_copy_and_difference(so, other);
15051511
}
15061512

15071513
/* If len(so) much more than len(other), it's more efficient to simply copy
15081514
* so and then iterate other looking for common elements. */
1509-
if ((PySet_GET_SIZE(so) >> 2) > PyObject_Size(other)) {
1515+
if ((PySet_GET_SIZE(so) >> 2) > other_size) {
15101516
return set_copy_and_difference(so, other);
15111517
}
15121518

0 commit comments

Comments
 (0)
0