bpo-30347: Stop crashes when concurrently iterate over itertools.groupby() iterators. (#1557)
This commit is contained in:
parent
114454e9f6
commit
c740e4fe8a
|
@ -2017,6 +2017,30 @@ class RegressionTests(unittest.TestCase):
|
|||
with self.assertRaises(StopIteration):
|
||||
next(it)
|
||||
|
||||
def test_issue30347_1(self):
|
||||
def f(n):
|
||||
if n == 5:
|
||||
list(b)
|
||||
return n != 6
|
||||
for (k, b) in groupby(range(10), f):
|
||||
list(b) # shouldn't crash
|
||||
|
||||
def test_issue30347_2(self):
|
||||
class K:
|
||||
def __init__(self, v):
|
||||
pass
|
||||
def __eq__(self, other):
|
||||
nonlocal i
|
||||
i += 1
|
||||
if i == 1:
|
||||
next(g, None)
|
||||
return True
|
||||
i = 0
|
||||
g = next(groupby(range(10), K))[1]
|
||||
for j in range(2):
|
||||
next(g, None) # shouldn't crash
|
||||
|
||||
|
||||
class SubclassWithKwargsTest(unittest.TestCase):
|
||||
def test_keywords_in_subclass(self):
|
||||
# count is not subclassable...
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Stop crashes when concurrently iterate over itertools.groupby() iterators.
|
|
@ -73,10 +73,37 @@ groupby_traverse(groupbyobject *gbo, visitproc visit, void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
groupby_step(groupbyobject *gbo)
|
||||
{
|
||||
PyObject *newvalue, *newkey, *oldvalue;
|
||||
|
||||
newvalue = PyIter_Next(gbo->it);
|
||||
if (newvalue == NULL)
|
||||
return -1;
|
||||
|
||||
if (gbo->keyfunc == Py_None) {
|
||||
newkey = newvalue;
|
||||
Py_INCREF(newvalue);
|
||||
} else {
|
||||
newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc, newvalue, NULL);
|
||||
if (newkey == NULL) {
|
||||
Py_DECREF(newvalue);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
oldvalue = gbo->currvalue;
|
||||
gbo->currvalue = newvalue;
|
||||
Py_XSETREF(gbo->currkey, newkey);
|
||||
Py_XDECREF(oldvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
groupby_next(groupbyobject *gbo)
|
||||
{
|
||||
PyObject *newvalue, *newkey, *r, *grouper;
|
||||
PyObject *r, *grouper;
|
||||
|
||||
gbo->currgrouper = NULL;
|
||||
/* skip to next iteration group */
|
||||
|
@ -95,25 +122,9 @@ groupby_next(groupbyobject *gbo)
|
|||
break;
|
||||
}
|
||||
|
||||
newvalue = PyIter_Next(gbo->it);
|
||||
if (newvalue == NULL)
|
||||
if (groupby_step(gbo) < 0)
|
||||
return NULL;
|
||||
|
||||
if (gbo->keyfunc == Py_None) {
|
||||
newkey = newvalue;
|
||||
Py_INCREF(newvalue);
|
||||
} else {
|
||||
newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc, newvalue, NULL);
|
||||
if (newkey == NULL) {
|
||||
Py_DECREF(newvalue);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Py_XSETREF(gbo->currkey, newkey);
|
||||
Py_XSETREF(gbo->currvalue, newvalue);
|
||||
}
|
||||
|
||||
Py_INCREF(gbo->currkey);
|
||||
Py_XSETREF(gbo->tgtkey, gbo->currkey);
|
||||
|
||||
|
@ -285,30 +296,14 @@ static PyObject *
|
|||
_grouper_next(_grouperobject *igo)
|
||||
{
|
||||
groupbyobject *gbo = (groupbyobject *)igo->parent;
|
||||
PyObject *newvalue, *newkey, *r;
|
||||
PyObject *r;
|
||||
int rcmp;
|
||||
|
||||
if (gbo->currgrouper != igo)
|
||||
return NULL;
|
||||
if (gbo->currvalue == NULL) {
|
||||
newvalue = PyIter_Next(gbo->it);
|
||||
if (newvalue == NULL)
|
||||
if (groupby_step(gbo) < 0)
|
||||
return NULL;
|
||||
|
||||
if (gbo->keyfunc == Py_None) {
|
||||
newkey = newvalue;
|
||||
Py_INCREF(newvalue);
|
||||
} else {
|
||||
newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc, newvalue, NULL);
|
||||
if (newkey == NULL) {
|
||||
Py_DECREF(newvalue);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
assert(gbo->currkey == NULL);
|
||||
gbo->currkey = newkey;
|
||||
gbo->currvalue = newvalue;
|
||||
}
|
||||
|
||||
assert(gbo->currkey != NULL);
|
||||
|
|
Loading…
Reference in New Issue