]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-106529: Fix subtle Tier 2 edge case with list iterator (#106756)
authorGuido van Rossum <guido@python.org>
Sat, 15 Jul 2023 00:22:06 +0000 (17:22 -0700)
committerGitHub <noreply@github.com>
Sat, 15 Jul 2023 00:22:06 +0000 (17:22 -0700)
The Tier 2 opcode _IS_ITER_EXHAUSTED_LIST (and _TUPLE)
didn't set it->it_seq to NULL, causing a subtle bug
that resulted in test_exhausted_iterator in list_tests.py
to fail when running all tests with -Xuops.

The bug was introduced in gh-106696.

Added this as an explicit test.

Also fixed the dependencies for ceval.o -- it depends on executor_cases.c.h.

Lib/test/test_capi/test_misc.py
Makefile.pre.in
Python/bytecodes.c
Python/executor_cases.c.h

index 43c04463236a2adc13abf0951c44cd94f1e039b9..6df918997b2b19118cf9a7bece3f9d5602b3427f 100644 (file)
@@ -2649,6 +2649,19 @@ class TestUops(unittest.TestCase):
         # Verification that the jump goes past END_FOR
         # is done by manual inspection of the output
 
+    def test_list_edge_case(self):
+        def testfunc(it):
+            for x in it:
+                pass
+
+        opt = _testinternalcapi.get_uop_optimizer()
+        with temporary_optimizer(opt):
+            a = [1, 2, 3]
+            it = iter(a)
+            testfunc(it)
+            a.append(4)
+            with self.assertRaises(StopIteration):
+                next(it)
 
 if __name__ == "__main__":
     unittest.main()
index ddf524ac17d72a4f92146ff30c89c5e600473d4e..553b2aa480c1845be6c7443f5e99ff256e7be813 100644 (file)
@@ -1564,6 +1564,7 @@ Python/ceval.o: \
                $(srcdir)/Python/ceval_macros.h \
                $(srcdir)/Python/condvar.h \
                $(srcdir)/Python/generated_cases.c.h \
+               $(srcdir)/Python/executor_cases.c.h \
                $(srcdir)/Include/internal/pycore_opcode_metadata.h \
                $(srcdir)/Python/opcode_targets.h
 
index 15b48ae9d82672c2995a72346cebf24721b9dbbe..3432b027713462e1905d78e0f58550e6593dffc7 100644 (file)
@@ -2448,7 +2448,12 @@ dummy_func(
             _PyListIterObject *it = (_PyListIterObject *)iter;
             assert(Py_TYPE(iter) == &PyListIter_Type);
             PyListObject *seq = it->it_seq;
-            if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) {
+            if (seq == NULL) {
+                exhausted = Py_True;
+            }
+            else if (it->it_index >= PyList_GET_SIZE(seq)) {
+                Py_DECREF(seq);
+                it->it_seq = NULL;
                 exhausted = Py_True;
             }
             else {
@@ -2499,7 +2504,12 @@ dummy_func(
             _PyTupleIterObject *it = (_PyTupleIterObject *)iter;
             assert(Py_TYPE(iter) == &PyTupleIter_Type);
             PyTupleObject *seq = it->it_seq;
-            if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) {
+            if (seq == NULL) {
+                exhausted = Py_True;
+            }
+            else if (it->it_index >= PyTuple_GET_SIZE(seq)) {
+                Py_DECREF(seq);
+                it->it_seq = NULL;
                 exhausted = Py_True;
             }
             else {
index 626baece814607922e26d08019359bf11d8016e1..ae21ffad94d801adfbde85c21ec7800d98b16afe 100644 (file)
             _PyListIterObject *it = (_PyListIterObject *)iter;
             assert(Py_TYPE(iter) == &PyListIter_Type);
             PyListObject *seq = it->it_seq;
-            if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) {
+            if (seq == NULL) {
+                exhausted = Py_True;
+            }
+            else if (it->it_index >= PyList_GET_SIZE(seq)) {
+                Py_DECREF(seq);
+                it->it_seq = NULL;
                 exhausted = Py_True;
             }
             else {
             _PyTupleIterObject *it = (_PyTupleIterObject *)iter;
             assert(Py_TYPE(iter) == &PyTupleIter_Type);
             PyTupleObject *seq = it->it_seq;
-            if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) {
+            if (seq == NULL) {
+                exhausted = Py_True;
+            }
+            else if (it->it_index >= PyTuple_GET_SIZE(seq)) {
+                Py_DECREF(seq);
+                it->it_seq = NULL;
                 exhausted = Py_True;
             }
             else {