diff options
author | Guido van Rossum <guido@python.org> | 2023-07-15 00:22:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-15 00:22:06 (GMT) |
commit | 0db85eeba762e72f9f3c027e432cdebc627aac6c (patch) | |
tree | c69c2bdbb1a9986cfc5a454a1e4995f89241a51e | |
parent | 03185f0c150ebc52d41dd5ea6f369c7b5ba9fc16 (diff) | |
download | cpython-0db85eeba762e72f9f3c027e432cdebc627aac6c.zip cpython-0db85eeba762e72f9f3c027e432cdebc627aac6c.tar.gz cpython-0db85eeba762e72f9f3c027e432cdebc627aac6c.tar.bz2 |
gh-106529: Fix subtle Tier 2 edge case with list iterator (#106756)
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.
-rw-r--r-- | Lib/test/test_capi/test_misc.py | 13 | ||||
-rw-r--r-- | Makefile.pre.in | 1 | ||||
-rw-r--r-- | Python/bytecodes.c | 14 | ||||
-rw-r--r-- | Python/executor_cases.c.h | 14 |
4 files changed, 38 insertions, 4 deletions
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 43c0446..6df9189 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -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() diff --git a/Makefile.pre.in b/Makefile.pre.in index ddf524a..553b2aa 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -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 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 15b48ae..3432b02 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -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 { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 626baec..ae21ffa 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1750,7 +1750,12 @@ _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 { @@ -1787,7 +1792,12 @@ _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 { |