Skip to content

Commit d0b9dc3

Browse files
[2.7] bpo-30347: Stop crashes when concurrently iterate over itertools.groupby() iterators. (GH-1557). (#3772)
(cherry picked from commit c740e4f)
1 parent 19eb87d commit d0b9dc3

File tree

3 files changed

+56
-46
lines changed

3 files changed

+56
-46
lines changed

‎Lib/test/test_itertools.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,29 @@ def test_long_chain_of_empty_iterables(self):
14731473
with self.assertRaises(StopIteration):
14741474
next(it)
14751475

1476+
def test_issue30347_1(self):
1477+
def f(n):
1478+
if n == 5:
1479+
list(b)
1480+
return n != 6
1481+
for (k, b) in groupby(range(10), f):
1482+
list(b) # shouldn't crash
1483+
1484+
def test_issue30347_2(self):
1485+
class K(object):
1486+
i = 0
1487+
def __init__(self, v):
1488+
pass
1489+
def __eq__(self, other):
1490+
K.i += 1
1491+
if K.i == 1:
1492+
next(g, None)
1493+
return True
1494+
g = next(groupby(range(10), K))[1]
1495+
for j in range(2):
1496+
next(g, None) # shouldn't crash
1497+
1498+
14761499
class SubclassWithKwargsTest(unittest.TestCase):
14771500
def test_keywords_in_subclass(self):
14781501
# count is not subclassable...
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Stop crashes when concurrently iterate over itertools.groupby() iterators.

‎Modules/itertoolsmodule.c‎

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,37 @@ groupby_traverse(groupbyobject *gbo, visitproc visit, void *arg)
7171
return 0;
7272
}
7373

74+
Py_LOCAL_INLINE(int)
75+
groupby_step(groupbyobject *gbo)
76+
{
77+
PyObject *newvalue, *newkey, *oldvalue;
78+
79+
newvalue = PyIter_Next(gbo->it);
80+
if (newvalue == NULL)
81+
return -1;
82+
83+
if (gbo->keyfunc == Py_None) {
84+
newkey = newvalue;
85+
Py_INCREF(newvalue);
86+
} else {
87+
newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc, newvalue, NULL);
88+
if (newkey == NULL) {
89+
Py_DECREF(newvalue);
90+
return -1;
91+
}
92+
}
93+
94+
oldvalue = gbo->currvalue;
95+
gbo->currvalue = newvalue;
96+
Py_XSETREF(gbo->currkey, newkey);
97+
Py_XDECREF(oldvalue);
98+
return 0;
99+
}
100+
74101
static PyObject *
75102
groupby_next(groupbyobject *gbo)
76103
{
77-
PyObject *newvalue, *newkey, *r, *grouper, *tmp;
104+
PyObject *r, *grouper;
78105

79106
/* skip to next iteration group */
80107
for (;;) {
@@ -93,35 +120,11 @@ groupby_next(groupbyobject *gbo)
93120
break;
94121
}
95122

96-
newvalue = PyIter_Next(gbo->it);
97-
if (newvalue == NULL)
123+
if (groupby_step(gbo) < 0)
98124
return NULL;
99-
100-
if (gbo->keyfunc == Py_None) {
101-
newkey = newvalue;
102-
Py_INCREF(newvalue);
103-
} else {
104-
newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc,
105-
newvalue, NULL);
106-
if (newkey == NULL) {
107-
Py_DECREF(newvalue);
108-
return NULL;
109-
}
110-
}
111-
112-
tmp = gbo->currkey;
113-
gbo->currkey = newkey;
114-
Py_XDECREF(tmp);
115-
116-
tmp = gbo->currvalue;
117-
gbo->currvalue = newvalue;
118-
Py_XDECREF(tmp);
119125
}
120-
121126
Py_INCREF(gbo->currkey);
122-
tmp = gbo->tgtkey;
123-
gbo->tgtkey = gbo->currkey;
124-
Py_XDECREF(tmp);
127+
Py_XSETREF(gbo->tgtkey, gbo->currkey);
125128

126129
grouper = _grouper_create(gbo, gbo->tgtkey);
127130
if (grouper == NULL)
@@ -229,29 +232,12 @@ static PyObject *
229232
_grouper_next(_grouperobject *igo)
230233
{
231234
groupbyobject *gbo = (groupbyobject *)igo->parent;
232-
PyObject *newvalue, *newkey, *r;
235+
PyObject *r;
233236
int rcmp;
234237

235238
if (gbo->currvalue == NULL) {
236-
newvalue = PyIter_Next(gbo->it);
237-
if (newvalue == NULL)
239+
if (groupby_step(gbo) < 0)
238240
return NULL;
239-
240-
if (gbo->keyfunc == Py_None) {
241-
newkey = newvalue;
242-
Py_INCREF(newvalue);
243-
} else {
244-
newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc,
245-
newvalue, NULL);
246-
if (newkey == NULL) {
247-
Py_DECREF(newvalue);
248-
return NULL;
249-
}
250-
}
251-
252-
assert(gbo->currkey == NULL);
253-
gbo->currkey = newkey;
254-
gbo->currvalue = newvalue;
255241
}
256242

257243
assert(gbo->currkey != NULL);

0 commit comments

Comments
 (0)