From e898626432a811fb000251efc12927cbd7c57836 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Mon, 12 Jan 2026 22:23:08 +0530 Subject: [PATCH 01/12] gh-143543: Fix re-entrant use-after-free in itertools.groupby --- Lib/test/test_itertools.py | 16 ++++++++++++++++ Modules/itertoolsmodule.c | 11 ++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 61bea9dba07fec..ff870bafe79aab 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -733,6 +733,22 @@ def keyfunc(obj): keyfunc.skip = 1 self.assertRaises(ExpectedError, gulp, [None, None], keyfunc) + def test_groupby_reentrant_eq_does_not_crash(self): + + class Key(bytearray): + seen = False + def __eq__(self, other): + if not Key.seen: + Key.seen = True + next(g) + return False + + data = [Key(b"a"), Key(b"b")] + + g = itertools.groupby(data) + next(g) + next(g) # must not segfault + def test_filter(self): self.assertEqual(list(filter(isEven, range(6))), [0,2,4]) self.assertEqual(list(filter(None, [0,1,0,2,0])), [1,2]) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 8685eff8be65c3..f20f538b47265f 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -545,8 +545,17 @@ groupby_next(PyObject *op) break; else { int rcmp; + PyObject *tgtkey = gbo->tgtkey; + PyObject *currkey = gbo->currkey; - rcmp = PyObject_RichCompareBool(gbo->tgtkey, gbo->currkey, Py_EQ); + Py_INCREF(tgtkey); + Py_INCREF(currkey); + + rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); + + Py_DECREF(tgtkey); + Py_DECREF(currkey); + if (rcmp == -1) return NULL; else if (rcmp == 0) From ba974bca279ae55feadbd099733cb61f82027d1e Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Mon, 12 Jan 2026 22:27:40 +0530 Subject: [PATCH 02/12] Fix whitespace per prek --- Modules/itertoolsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index f20f538b47265f..c7573cf9551303 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -555,7 +555,7 @@ groupby_next(PyObject *op) Py_DECREF(tgtkey); Py_DECREF(currkey); - + if (rcmp == -1) return NULL; else if (rcmp == 0) From 0debc2a0bd1fd2e3a7f7036e9215289733a37e34 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 08:48:44 +0530 Subject: [PATCH 03/12] Add NEWS entry for itertools.groupby crash fix --- Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst b/Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst new file mode 100644 index 00000000000000..b74ed28fc0424e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst @@ -0,0 +1,2 @@ +Fix a crash in itertools.groupby that could occur when a user-defined +__eq__ method re-enters the iterator during key comparison. \ No newline at end of file From 8d831767d3ee54448b3c8d0e038a0fc0258a8ff6 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 08:52:03 +0530 Subject: [PATCH 04/12] Fix NEWS filename for gh-143543 --- Misc/NEWS.d/next/Library/gh-143543.Library.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/gh-143543.Library.rst diff --git a/Misc/NEWS.d/next/Library/gh-143543.Library.rst b/Misc/NEWS.d/next/Library/gh-143543.Library.rst new file mode 100644 index 00000000000000..b74ed28fc0424e --- /dev/null +++ b/Misc/NEWS.d/next/Library/gh-143543.Library.rst @@ -0,0 +1,2 @@ +Fix a crash in itertools.groupby that could occur when a user-defined +__eq__ method re-enters the iterator during key comparison. \ No newline at end of file From ca932bf3433216f30b038fc47ced40082129d50a Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 08:55:28 +0530 Subject: [PATCH 05/12] Fix NEWS entry type for gh-143543 --- Misc/NEWS.d/next/Library/gh-143543.bugfix.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/gh-143543.bugfix.rst diff --git a/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst b/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst new file mode 100644 index 00000000000000..b74ed28fc0424e --- /dev/null +++ b/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst @@ -0,0 +1,2 @@ +Fix a crash in itertools.groupby that could occur when a user-defined +__eq__ method re-enters the iterator during key comparison. \ No newline at end of file From 0e86303246ba709a7ecfbd871214899171ef8642 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 09:08:23 +0530 Subject: [PATCH 06/12] Remove incorrect NEWS files for gh-143543 --- Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst | 2 -- Misc/NEWS.d/next/Library/gh-143543.Library.rst | 2 -- 2 files changed, 4 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst delete mode 100644 Misc/NEWS.d/next/Library/gh-143543.Library.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst b/Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst deleted file mode 100644 index b74ed28fc0424e..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-01-13-itertools-groupby-uaf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in itertools.groupby that could occur when a user-defined -__eq__ method re-enters the iterator during key comparison. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/gh-143543.Library.rst b/Misc/NEWS.d/next/Library/gh-143543.Library.rst deleted file mode 100644 index b74ed28fc0424e..00000000000000 --- a/Misc/NEWS.d/next/Library/gh-143543.Library.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash in itertools.groupby that could occur when a user-defined -__eq__ method re-enters the iterator during key comparison. \ No newline at end of file From 740218ccfe96ab468263a0f5c09a8c54628e7e44 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 09:23:09 +0530 Subject: [PATCH 07/12] Avoid borrowed references during groupby key comparison --- Modules/itertoolsmodule.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index c7573cf9551303..861cbd86e7716f 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -548,13 +548,15 @@ groupby_next(PyObject *op) PyObject *tgtkey = gbo->tgtkey; PyObject *currkey = gbo->currkey; - Py_INCREF(tgtkey); - Py_INCREF(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(tgtkey); - Py_DECREF(currkey); + Py_DECREF(gbo -> tgtkey); + Py_DECREF(gbo -> currkey); if (rcmp == -1) return NULL; From e3a54be56f0739c46983285a7825c35e80a1367c Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 09:33:36 +0530 Subject: [PATCH 08/12] Clarify NEWS entry wording --- Misc/NEWS.d/next/Library/gh-143543.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst b/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst index b74ed28fc0424e..efc2e292e14d20 100644 --- a/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst +++ b/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst @@ -1,2 +1,2 @@ Fix a crash in itertools.groupby that could occur when a user-defined -__eq__ method re-enters the iterator during key comparison. \ No newline at end of file +:meth:`~object.__eq__` method re-enters the iterator during key comparison. \ No newline at end of file From 998334526afc8d636572e30a831697aaf6c2e70b Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 10:25:44 +0530 Subject: [PATCH 09/12] Fix refcounting during groupby key comparison --- Modules/itertoolsmodule.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 861cbd86e7716f..ef9d2668364aca 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -550,13 +550,15 @@ groupby_next(PyObject *op) /* 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); + PyObject *tgtkey = gbo->tgtkey; + PyObject *currkey = gbo->currkey; + Py_INCREF(tgtkey); + Py_INCREF(currkey); rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); - Py_DECREF(gbo -> tgtkey); - Py_DECREF(gbo -> currkey); + Py_DECREF(tgtkey); + Py_DECREF(currkey); if (rcmp == -1) return NULL; From 1ea51c06d7afcdbded3acf9d50e4a90736c615a9 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 10:42:29 +0530 Subject: [PATCH 10/12] Add NEWS entry via blurb for itertools.groupby crash --- ...ugfix.rst => 2026-01-13-10-38-43.gh-issue-143543.DeQRCO.rst} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Misc/NEWS.d/next/Library/{gh-143543.bugfix.rst => 2026-01-13-10-38-43.gh-issue-143543.DeQRCO.rst} (91%) diff --git a/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst b/Misc/NEWS.d/next/Library/2026-01-13-10-38-43.gh-issue-143543.DeQRCO.rst similarity index 91% rename from Misc/NEWS.d/next/Library/gh-143543.bugfix.rst rename to Misc/NEWS.d/next/Library/2026-01-13-10-38-43.gh-issue-143543.DeQRCO.rst index efc2e292e14d20..14622a395ec22e 100644 --- a/Misc/NEWS.d/next/Library/gh-143543.bugfix.rst +++ b/Misc/NEWS.d/next/Library/2026-01-13-10-38-43.gh-issue-143543.DeQRCO.rst @@ -1,2 +1,2 @@ Fix a crash in itertools.groupby that could occur when a user-defined -:meth:`~object.__eq__` method re-enters the iterator during key comparison. \ No newline at end of file +:meth:`~object.__eq__` method re-enters the iterator during key comparison. From 336c36748ab272ce0f980b19121084338d72772a Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 10:51:13 +0530 Subject: [PATCH 11/12] Fix duplicate variable declarations in groupby_next --- Modules/itertoolsmodule.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index ef9d2668364aca..7a80d019fad5b3 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -545,20 +545,16 @@ groupby_next(PyObject *op) break; else { int rcmp; - 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. */ - PyObject *tgtkey = gbo->tgtkey; - PyObject *currkey = gbo->currkey; - Py_INCREF(tgtkey); - Py_INCREF(currkey); + Py_INCREF(gbo -> tgtkey); + Py_INCREF(gbo -> currkey); rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); - Py_DECREF(tgtkey); - Py_DECREF(currkey); + Py_DECREF(gbo -> tgtkey); + Py_DECREF(gbo -> currkey); if (rcmp == -1) return NULL; From 9cbe1a6c3651ddde58eb9b388ff861a39205a058 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 13 Jan 2026 10:59:57 +0530 Subject: [PATCH 12/12] itertools: hold strong references during groupby key comparison --- Modules/itertoolsmodule.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 7a80d019fad5b3..df04a73f374a1b 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -545,16 +545,18 @@ groupby_next(PyObject *op) break; else { int rcmp; - + 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(gbo -> tgtkey); - Py_INCREF(gbo -> currkey); + Py_INCREF(tgtkey); + Py_INCREF(currkey); rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); - Py_DECREF(gbo -> tgtkey); - Py_DECREF(gbo -> currkey); + Py_DECREF(tgtkey); + Py_DECREF(currkey); if (rcmp == -1) return NULL;