From 574cb3474e1b9d4f2a9bca9ea238751d6c14e575 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Sat, 10 Jan 2026 01:42:11 +0530 Subject: [PATCH 1/3] Fix heap buffer overflow in set_clear_internal (GH-143546) Added a bounds check in set_clear_internal to prevent heap buffer overflow when the set is mutated re-entrantly during iteration (e.g. via __eq__). Added regression test in Lib/test/test_set.py. --- Lib/test/test_set.py | 36 ++++++++++++++++++++++++++++++++++++ Objects/setobject.c | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 203a231201c669..239be5eed5810a 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -676,6 +676,42 @@ def __hash__(self): myset.discard(elem2) + + def test_reentrant_clear_in_iand(self): + # Issue 143546: Heap buffer overflow in set_clear_internal + # via re-entrant __eq__ during set_iand + import random + aux = {object()} + targets = [] + + class Victim: + def __hash__(self): return 0 + def __eq__(self, other): return NotImplemented + + class Trigger: + def __hash__(self): return 0 + def __eq__(self, other): + if not targets: return False + for s in targets: + op = random.randrange(7) + if op == 0: s.clear() + elif op == 1: s.add(Victim()) + elif op == 2: s.discard(Victim()) + else: s ^= aux + return False + + random.seed(0) + for _ in range(50): + left = {Victim() for _ in range(6)} + right = {Victim() for _ in range(6)} + for _ in range(3): + right.add(Trigger()) + targets[:] = [left, right] + try: + left &= right + except (RuntimeError, IndexError): + pass + class SetSubclass(set): pass diff --git a/Objects/setobject.c b/Objects/setobject.c index 55e30fe2cdd8f7..24cdd7f3df9a8e 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -678,7 +678,7 @@ set_clear_internal(PyObject *self) * assert that the refcount on table is 1 now, i.e. that this function * has unique access to it, so decref side-effects can't alter it. */ - for (entry = table; used > 0; entry++) { + for (entry = table; used > 0 && entry < table + oldsize; entry++) { if (entry->key && entry->key != dummy) { used--; Py_DECREF(entry->key); From 8d4b3d8699353583c9cfbb21bd804efac72eea3f Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Sat, 10 Jan 2026 02:16:51 +0530 Subject: [PATCH 2/3] Add news entry for gh-143546 --- .../2026-01-10-01-46-00.gh-issue-143546.fixed.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst new file mode 100644 index 00000000000000..1165db8abe90d2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst @@ -0,0 +1 @@ +Fixed a heap buffer overflow in :func:`set_clear_internal` logic when a set is mutated re-entrantly during an operation. From d95abed40321fc5632d70c884ab29b01fec092b9 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Sat, 10 Jan 2026 11:23:27 +0530 Subject: [PATCH 3/3] Update news entry to omit internal function details and fix docs failure --- .../2026-01-10-01-46-00.gh-issue-143546.fixed.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst index 1165db8abe90d2..0049fabb56a8fb 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-01-46-00.gh-issue-143546.fixed.rst @@ -1 +1 @@ -Fixed a heap buffer overflow in :func:`set_clear_internal` logic when a set is mutated re-entrantly during an operation. +Fixed a heap buffer overflow in the set execution logic when a set is mutated re-entrantly during an intersection operation.