Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork34.2k
Open
Description
Description
_grouper_next() inModules/itertoolsmodule.c passesigo->tgtkey andgbo->currkey directly toPyObject_RichCompareBool() without holding strong references to them first.
A user-defined__eq__ method can re-enter the parentgroupby iterator during that comparison. Re-entry callsgroupby_step(), which contains:
Py_XSETREF(gbo->currkey,newkey);
This freesgbo->currkey while it is still being compared — a use-after-free.
Relationship togh-143543
gh-143543 fixed the same bug ingroupby_next() by taking INCREF'd local snapshots before callingPyObject_RichCompareBool(). The fix was not applied to the analogous code in_grouper_next().
Fix
Apply the same INCREF snapshot pattern used in thegroupby_next() fix:
PyObject*tgtkey=igo->tgtkey;PyObject*currkey=gbo->currkey;Py_INCREF(tgtkey);Py_INCREF(currkey);rcmp=PyObject_RichCompareBool(tgtkey,currkey,Py_EQ);Py_DECREF(tgtkey);Py_DECREF(currkey);
Reproducer
importitertoolsouter_grouper=NoneclassKey:def__init__(self,val,do_advance):self.val=valself.do_advance=do_advancedef__eq__(self,other):ifself.do_advance:self.do_advance=Falsetry:next(outer_grouper)exceptStopIteration:passreturnNotImplementedreturnself.val==other.valdef__hash__(self):returnhash(self.val)values= [1,1,2]keys_iter=iter([Key(1,True),Key(1,False),Key(2,False)])g=itertools.groupby(values,lambda_:next(keys_iter))outer_grouper=gk,grp=next(g)list(grp)# use-after-free / crash under ASAN