Skip to content

Commit 8f0f205

Browse files
Issue python#28322: Fixed possible crashes when unpickle itertools objects from
incorrect pickle data. Based on patch by John Leitch.
2 parents bf090e3 + 85c3f26 commit 8f0f205

3 files changed

Lines changed: 57 additions & 10 deletions

File tree

Lib/test/test_itertools.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ def test_chain_reducible(self):
183183
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
184184
self.pickletest(proto, chain('abc', 'def'), compare=list('abcdef'))
185185

186+
def test_chain_setstate(self):
187+
self.assertRaises(TypeError, chain().__setstate__, ())
188+
self.assertRaises(TypeError, chain().__setstate__, [])
189+
self.assertRaises(TypeError, chain().__setstate__, 0)
190+
self.assertRaises(TypeError, chain().__setstate__, ([],))
191+
self.assertRaises(TypeError, chain().__setstate__, (iter([]), []))
192+
it = chain()
193+
it.__setstate__((iter(['abc', 'def']),))
194+
self.assertEqual(list(it), ['a', 'b', 'c', 'd', 'e', 'f'])
195+
it = chain()
196+
it.__setstate__((iter(['abc', 'def']), iter(['ghi'])))
197+
self.assertEqual(list(it), ['ghi', 'a', 'b', 'c', 'd', 'e', 'f'])
198+
186199
def test_combinations(self):
187200
self.assertRaises(TypeError, combinations, 'abc') # missing r argument
188201
self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments
@@ -667,19 +680,22 @@ def test_cycle_setstate(self):
667680
self.assertEqual(take(20, c), list('defgabcdefgabcdefgab'))
668681

669682
# The first argument to setstate needs to be a tuple
670-
with self.assertRaises(SystemError):
683+
with self.assertRaises(TypeError):
671684
cycle('defg').__setstate__([list('abcdefg'), 0])
672685

673686
# The first argument in the setstate tuple must be a list
674687
with self.assertRaises(TypeError):
675688
c = cycle('defg')
676-
c.__setstate__((dict.fromkeys('defg'), 0))
677-
take(20, c)
689+
c.__setstate__((tuple('defg'), 0))
690+
take(20, c)
678691

679-
# The first argument in the setstate tuple must be a list
692+
# The second argument in the setstate tuple must be an int
680693
with self.assertRaises(TypeError):
681694
cycle('defg').__setstate__((list('abcdefg'), 'x'))
682695

696+
self.assertRaises(TypeError, cycle('').__setstate__, ())
697+
self.assertRaises(TypeError, cycle('').__setstate__, ([],))
698+
683699
def test_groupby(self):
684700
# Check whether it accepts arguments correctly
685701
self.assertEqual([], list(groupby([])))

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Core and Builtins
4646
Library
4747
-------
4848

49+
- Issue #28322: Fixed possible crashes when unpickle itertools objects from
50+
incorrect pickle data. Based on patch by John Leitch.
51+
4952
- Issue #28228: imghdr now supports pathlib.
5053

5154
- Issue #28226: compileall now supports pathlib.

Modules/itertoolsmodule.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,13 @@ static PyObject *
147147
groupby_setstate(groupbyobject *lz, PyObject *state)
148148
{
149149
PyObject *currkey, *currvalue, *tgtkey;
150-
if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey))
150+
if (!PyTuple_Check(state)) {
151+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
151152
return NULL;
153+
}
154+
if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) {
155+
return NULL;
156+
}
152157
Py_INCREF(currkey);
153158
Py_XSETREF(lz->currkey, currkey);
154159
Py_INCREF(currvalue);
@@ -727,8 +732,13 @@ tee_setstate(teeobject *to, PyObject *state)
727732
{
728733
teedataobject *tdo;
729734
int index;
730-
if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index))
735+
if (!PyTuple_Check(state)) {
736+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
737+
return NULL;
738+
}
739+
if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) {
731740
return NULL;
741+
}
732742
if (index < 0 || index > LINKCELLS) {
733743
PyErr_SetString(PyExc_ValueError, "Index out of range");
734744
return NULL;
@@ -971,9 +981,13 @@ cycle_setstate(cycleobject *lz, PyObject *state)
971981
{
972982
PyObject *saved=NULL;
973983
int firstpass;
974-
975-
if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass))
984+
if (!PyTuple_Check(state)) {
985+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
986+
return NULL;
987+
}
988+
if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) {
976989
return NULL;
990+
}
977991
Py_INCREF(saved);
978992
Py_XSETREF(lz->saved, saved);
979993
lz->firstpass = firstpass != 0;
@@ -1903,8 +1917,17 @@ chain_setstate(chainobject *lz, PyObject *state)
19031917
{
19041918
PyObject *source, *active=NULL;
19051919

1906-
if (! PyArg_ParseTuple(state, "O|O", &source, &active))
1920+
if (!PyTuple_Check(state)) {
1921+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
1922+
return NULL;
1923+
}
1924+
if (!PyArg_ParseTuple(state, "O|O", &source, &active)) {
1925+
return NULL;
1926+
}
1927+
if (!PyIter_Check(source) || (active != NULL && !PyIter_Check(active))) {
1928+
PyErr_SetString(PyExc_TypeError, "Arguments must be iterators.");
19071929
return NULL;
1930+
}
19081931

19091932
Py_INCREF(source);
19101933
Py_XSETREF(lz->source, source);
@@ -3262,10 +3285,15 @@ permutations_setstate(permutationsobject *po, PyObject *state)
32623285
PyObject *indices, *cycles, *result;
32633286
Py_ssize_t n, i;
32643287

3288+
if (!PyTuple_Check(state)) {
3289+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
3290+
return NULL;
3291+
}
32653292
if (!PyArg_ParseTuple(state, "O!O!",
32663293
&PyTuple_Type, &indices,
3267-
&PyTuple_Type, &cycles))
3294+
&PyTuple_Type, &cycles)) {
32683295
return NULL;
3296+
}
32693297

32703298
n = PyTuple_GET_SIZE(po->pool);
32713299
if (PyTuple_GET_SIZE(indices) != n || PyTuple_GET_SIZE(cycles) != po->r) {

0 commit comments

Comments
 (0)