From e898626432a811fb000251efc12927cbd7c57836 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Mon, 12 Jan 2026 22:23:08 +0530 Subject: [PATCH 01/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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; From 8c61450233d9cea60df098e63e9de4aead7d224c Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Wed, 14 Jan 2026 08:43:45 +0530 Subject: [PATCH 13/19] Clarify re-entrant groupby key comparison comment --- Modules/itertoolsmodule.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index df04a73f374a1b..cdb4dea4dcbc0d 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -545,11 +545,14 @@ groupby_next(PyObject *op) break; else { int rcmp; + + /* A user-defined __eq__ can re-enter groupby and advance the iterator, + mutating gbo->tgtkey / gbo->currkey while we are comparing them. + Take local snapshots and hold strong references so INCREF/DECREF + apply to the same objects even under re-entrancy. */ 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); From 90e995b1b817ca47ee17dc90d7e68bfa888811c2 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 <148854295+VanshAgarwal24036@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:49:30 +0530 Subject: [PATCH 14/19] Update Modules/itertoolsmodule.c Co-authored-by: Sergey B Kirpichev --- Modules/itertoolsmodule.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index cdb4dea4dcbc0d..1cb24e1b3d5f54 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -547,9 +547,9 @@ groupby_next(PyObject *op) int rcmp; /* A user-defined __eq__ can re-enter groupby and advance the iterator, - mutating gbo->tgtkey / gbo->currkey while we are comparing them. - Take local snapshots and hold strong references so INCREF/DECREF - apply to the same objects even under re-entrancy. */ + mutating gbo->tgtkey / gbo->currkey while we are comparing them. + Take local snapshots and hold strong references so INCREF/DECREF + apply to the same objects even under re-entrancy. */ PyObject *tgtkey = gbo->tgtkey; PyObject *currkey = gbo->currkey; From 4f2338f1c50fc29ffeed0da2d8491ad6f500a569 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 <148854295+VanshAgarwal24036@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:50:33 +0530 Subject: [PATCH 15/19] Update Lib/test/test_itertools.py Co-authored-by: Sergey B Kirpichev --- Lib/test/test_itertools.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index ff870bafe79aab..0fa98abad57a8a 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -734,7 +734,6 @@ def keyfunc(obj): 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): From 2cac26be898e86976f2211387fd82e2a1cfa7236 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Wed, 14 Jan 2026 18:55:17 +0530 Subject: [PATCH 16/19] Simplify groupby re-entrancy test --- Lib/test/test_itertools.py | 4 +--- Modules/itertoolsmodule.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 0fa98abad57a8a..38df89455f0ab9 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -742,9 +742,7 @@ def __eq__(self, other): next(g) return False - data = [Key(b"a"), Key(b"b")] - - g = itertools.groupby(data) + g = itertools.groupby([Key(b"a"), Key(b"b")]) next(g) next(g) # must not segfault diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 1cb24e1b3d5f54..dff45e044bef9e 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -544,7 +544,6 @@ groupby_next(PyObject *op) else if (gbo->tgtkey == NULL) break; else { - int rcmp; /* A user-defined __eq__ can re-enter groupby and advance the iterator, mutating gbo->tgtkey / gbo->currkey while we are comparing them. @@ -556,7 +555,7 @@ groupby_next(PyObject *op) Py_INCREF(tgtkey); Py_INCREF(currkey); - rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); + int rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); Py_DECREF(tgtkey); Py_DECREF(currkey); From fed7db70b1fccd0e9d67fa3631c21ec0de3556c7 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Wed, 14 Jan 2026 19:16:41 +0530 Subject: [PATCH 17/19] Move rcmp declaration and clarify re-entrancy comment --- Modules/itertoolsmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index dff45e044bef9e..1cb24e1b3d5f54 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -544,6 +544,7 @@ groupby_next(PyObject *op) else if (gbo->tgtkey == NULL) break; else { + int rcmp; /* A user-defined __eq__ can re-enter groupby and advance the iterator, mutating gbo->tgtkey / gbo->currkey while we are comparing them. @@ -555,7 +556,7 @@ groupby_next(PyObject *op) Py_INCREF(tgtkey); Py_INCREF(currkey); - int rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); + rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); Py_DECREF(tgtkey); Py_DECREF(currkey); From 4939083e12339646ff3dea681760e282b4fb0c74 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Wed, 14 Jan 2026 19:28:05 +0530 Subject: [PATCH 18/19] Move comment before declarations and inline rcmp --- Modules/itertoolsmodule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 1cb24e1b3d5f54..dff45e044bef9e 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -544,7 +544,6 @@ groupby_next(PyObject *op) else if (gbo->tgtkey == NULL) break; else { - int rcmp; /* A user-defined __eq__ can re-enter groupby and advance the iterator, mutating gbo->tgtkey / gbo->currkey while we are comparing them. @@ -556,7 +555,7 @@ groupby_next(PyObject *op) Py_INCREF(tgtkey); Py_INCREF(currkey); - rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); + int rcmp = PyObject_RichCompareBool(tgtkey, currkey, Py_EQ); Py_DECREF(tgtkey); Py_DECREF(currkey); From e42b9b419c30f47177b62188fbc9c6d287f4f801 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Wed, 14 Jan 2026 20:08:24 +0530 Subject: [PATCH 19/19] Remove Extra lines --- Modules/itertoolsmodule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index dff45e044bef9e..9a064463d88f55 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -544,7 +544,6 @@ groupby_next(PyObject *op) else if (gbo->tgtkey == NULL) break; else { - /* A user-defined __eq__ can re-enter groupby and advance the iterator, mutating gbo->tgtkey / gbo->currkey while we are comparing them. Take local snapshots and hold strong references so INCREF/DECREF