Skip to content

Conversation

@VanshAgarwal24036
Copy link
Contributor

@VanshAgarwal24036 VanshAgarwal24036 commented Jan 12, 2026

Fix a use-after-free in itertools.groupby when a user-defined eq
re-enters next(groupby) during key comparison.

groupby_next() compared borrowed references to currkey and tgtkey using
PyObject_RichCompareBool(). A re-entrant eq could advance the iterator,
replace and decref those keys, leaving the outer comparison accessing
freed memory.

The fix temporarily INCREFs both keys for the duration of the comparison,
preventing re-entrancy from invalidating them. A regression test is added.

@VanshAgarwal24036
Copy link
Contributor Author

Skip News

@picnixz
Copy link
Member

picnixz commented Jan 12, 2026

Skip News

No. This is a bug fix that is impacting end users. In the future, please let triagers decide which labels to use when the bot doesn't do it automatically.

@VanshAgarwal24036
Copy link
Contributor Author

Thanks for the clarification — I’ve added a NEWS entry documenting the user-visible crash fix.

Copy link
Member

@skirpichev skirpichev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skirpichev
Copy link
Member

In order to keep the commit history intact, please avoid squashing or amending history and then force-pushing to the PR. Reviewers often want to look at individual commits. When the PR is merged, everything will be squashed into a single commit.

@skirpichev
Copy link
Member

@VanshAgarwal24036, please avoid force pushes!

@VanshAgarwal24036
Copy link
Contributor Author

Thanks for the clarification — understood. I won’t rewrite history or use force-pushes going forward and will only add new commits.

I’m still seeing bedevere/news failing in CI, and I want to make sure I’m following the expected workflow correctly. Would you prefer that I delete the current NEWS entry and re-add it using blurb add, or should I keep the existing file and adjust it further?

Please let me know the preferred approach and I’ll follow that.

Comment on lines +548 to +559
PyObject *tgtkey = gbo->tgtkey;
PyObject *currkey = gbo->currkey;

/* Hold strong references during comparison to prevent re-entrant __eq__
from advancing the iterator and invalidating borrowed references. */
Py_INCREF(tgtkey);
Py_INCREF(currkey);

rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ);

Py_DECREF(tgtkey);
Py_DECREF(currkey);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PyObject *tgtkey = gbo->tgtkey;
PyObject *currkey = gbo->currkey;
/* Hold strong references during comparison to prevent re-entrant __eq__
from advancing the iterator and invalidating borrowed references. */
Py_INCREF(tgtkey);
Py_INCREF(currkey);
rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ);
Py_DECREF(tgtkey);
Py_DECREF(currkey);
/* Hold strong references during comparison to prevent re-entrant __eq__
from advancing the iterator and invalidating borrowed references. */
Py_INCREF(gbo->tgtkey);
Py_INCREF(gbo->currkey);
rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ);
Py_DECREF(gbo->tgtkey);
Py_DECREF(gbo->currkey);

Maybe you want also to remove a separate declaration of rcmp and add a comment, explaining why we do Py_INCREF here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion!
I kept local snapshots of tgtkey / currkey instead, because a re-entrant eq can mutate gbo->tgtkey / gbo->currkey, and INCREF/DECREF must apply to the same objects.
This avoids refcount mismatches under ASan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants