Skip to content

Commit 85c3f26

Browse files
Issue python#28322: Fixed possible crashes when unpickle itertools objects from
incorrect pickle data. Based on patch by John Leitch.
1 parent 38317d3 commit 85c3f26

3 files changed

Lines changed: 70 additions & 5 deletions

File tree

Lib/test/test_itertools.py

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

187+
def test_chain_setstate(self):
188+
self.assertRaises(TypeError, chain().__setstate__, ())
189+
self.assertRaises(TypeError, chain().__setstate__, [])
190+
self.assertRaises(TypeError, chain().__setstate__, 0)
191+
self.assertRaises(TypeError, chain().__setstate__, ([],))
192+
self.assertRaises(TypeError, chain().__setstate__, (iter([]), []))
193+
it = chain()
194+
it.__setstate__((iter(['abc', 'def']),))
195+
self.assertEqual(list(it), ['a', 'b', 'c', 'd', 'e', 'f'])
196+
it = chain()
197+
it.__setstate__((iter(['abc', 'def']), iter(['ghi'])))
198+
self.assertEqual(list(it), ['ghi', 'a', 'b', 'c', 'd', 'e', 'f'])
199+
187200
def test_combinations(self):
188201
self.assertRaises(TypeError, combinations, 'abc') # missing r argument
189202
self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments
@@ -631,6 +644,25 @@ def test_cycle(self):
631644
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
632645
self.pickletest(proto, cycle('abc'))
633646

647+
def test_cycle_setstate(self):
648+
self.assertRaises(TypeError, cycle('').__setstate__, ())
649+
self.assertRaises(TypeError, cycle('').__setstate__, [])
650+
self.assertRaises(TypeError, cycle('').__setstate__, 0)
651+
self.assertRaises(TypeError, cycle('').__setstate__, ([],))
652+
self.assertRaises(TypeError, cycle('').__setstate__, ((), 0))
653+
it = cycle('abc')
654+
it.__setstate__((['de', 'fg'], 0))
655+
self.assertEqual(list(islice(it, 15)),
656+
['a', 'b', 'c', 'de', 'fg',
657+
'a', 'b', 'c', 'de', 'fg',
658+
'a', 'b', 'c', 'de', 'fg'])
659+
it = cycle('abc')
660+
it.__setstate__((['de', 'fg'], 1))
661+
self.assertEqual(list(islice(it, 15)),
662+
['a', 'b', 'c', 'de', 'fg',
663+
'de', 'fg', 'de', 'fg', 'de',
664+
'fg', 'de', 'fg', 'de', 'fg'])
665+
634666
def test_groupby(self):
635667
# Check whether it accepts arguments correctly
636668
self.assertEqual([], list(groupby([])))

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ Core and Builtins
8585
Library
8686
-------
8787

88+
- Issue #28322: Fixed possible crashes when unpickle itertools objects from
89+
incorrect pickle data. Based on patch by John Leitch.
90+
8891
- Issue #1703178: Fix the ability to pass the --link-objects option to the
8992
distutils build_ext command.
9093

Modules/itertoolsmodule.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,13 @@ static PyObject *
155155
groupby_setstate(groupbyobject *lz, PyObject *state)
156156
{
157157
PyObject *currkey, *currvalue, *tgtkey;
158-
if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey))
158+
if (!PyTuple_Check(state)) {
159+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
159160
return NULL;
161+
}
162+
if (!PyArg_ParseTuple(state, "OOO", &currkey, &currvalue, &tgtkey)) {
163+
return NULL;
164+
}
160165
Py_INCREF(currkey);
161166
Py_XSETREF(lz->currkey, currkey);
162167
Py_INCREF(currvalue);
@@ -736,8 +741,13 @@ tee_setstate(teeobject *to, PyObject *state)
736741
{
737742
teedataobject *tdo;
738743
int index;
739-
if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index))
744+
if (!PyTuple_Check(state)) {
745+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
746+
return NULL;
747+
}
748+
if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) {
740749
return NULL;
750+
}
741751
if (index < 0 || index > LINKCELLS) {
742752
PyErr_SetString(PyExc_ValueError, "Index out of range");
743753
return NULL;
@@ -966,8 +976,13 @@ cycle_setstate(cycleobject *lz, PyObject *state)
966976
{
967977
PyObject *saved=NULL;
968978
int firstpass;
969-
if (!PyArg_ParseTuple(state, "Oi", &saved, &firstpass))
979+
if (!PyTuple_Check(state)) {
980+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
981+
return NULL;
982+
}
983+
if (!PyArg_ParseTuple(state, "O!i", &PyList_Type, &saved, &firstpass)) {
970984
return NULL;
985+
}
971986
Py_XINCREF(saved);
972987
Py_XSETREF(lz->saved, saved);
973988
lz->firstpass = firstpass != 0;
@@ -1891,8 +1906,18 @@ static PyObject *
18911906
chain_setstate(chainobject *lz, PyObject *state)
18921907
{
18931908
PyObject *source, *active=NULL;
1894-
if (! PyArg_ParseTuple(state, "O|O", &source, &active))
1909+
1910+
if (!PyTuple_Check(state)) {
1911+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
1912+
return NULL;
1913+
}
1914+
if (!PyArg_ParseTuple(state, "O|O", &source, &active)) {
1915+
return NULL;
1916+
}
1917+
if (!PyIter_Check(source) || (active != NULL && !PyIter_Check(active))) {
1918+
PyErr_SetString(PyExc_TypeError, "Arguments must be iterators.");
18951919
return NULL;
1920+
}
18961921

18971922
Py_INCREF(source);
18981923
Py_XSETREF(lz->source, source);
@@ -3251,10 +3276,15 @@ permutations_setstate(permutationsobject *po, PyObject *state)
32513276
PyObject *indices, *cycles, *result;
32523277
Py_ssize_t n, i;
32533278

3279+
if (!PyTuple_Check(state)) {
3280+
PyErr_SetString(PyExc_TypeError, "state is not a tuple");
3281+
return NULL;
3282+
}
32543283
if (!PyArg_ParseTuple(state, "O!O!",
32553284
&PyTuple_Type, &indices,
3256-
&PyTuple_Type, &cycles))
3285+
&PyTuple_Type, &cycles)) {
32573286
return NULL;
3287+
}
32583288

32593289
n = PyTuple_GET_SIZE(po->pool);
32603290
if (PyTuple_GET_SIZE(indices) != n ||

0 commit comments

Comments
 (0)