Skip to content

Commit 0db85ee

Browse files
authored
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.
1 parent 03185f0 commit 0db85ee

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

Lib/test/test_capi/test_misc.py

+13
Original file line numberDiff line numberDiff line change
@@ -2649,6 +2649,19 @@ def testfunc(a):
26492649
# Verification that the jump goes past END_FOR
26502650
# is done by manual inspection of the output
26512651

2652+
def test_list_edge_case(self):
2653+
def testfunc(it):
2654+
for x in it:
2655+
pass
2656+
2657+
opt = _testinternalcapi.get_uop_optimizer()
2658+
with temporary_optimizer(opt):
2659+
a = [1, 2, 3]
2660+
it = iter(a)
2661+
testfunc(it)
2662+
a.append(4)
2663+
with self.assertRaises(StopIteration):
2664+
next(it)
26522665

26532666
if __name__ == "__main__":
26542667
unittest.main()

Makefile.pre.in

+1
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,7 @@ Python/ceval.o: \
15641564
$(srcdir)/Python/ceval_macros.h \
15651565
$(srcdir)/Python/condvar.h \
15661566
$(srcdir)/Python/generated_cases.c.h \
1567+
$(srcdir)/Python/executor_cases.c.h \
15671568
$(srcdir)/Include/internal/pycore_opcode_metadata.h \
15681569
$(srcdir)/Python/opcode_targets.h
15691570

Python/bytecodes.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -2448,7 +2448,12 @@ dummy_func(
24482448
_PyListIterObject *it = (_PyListIterObject *)iter;
24492449
assert(Py_TYPE(iter) == &PyListIter_Type);
24502450
PyListObject *seq = it->it_seq;
2451-
if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) {
2451+
if (seq == NULL) {
2452+
exhausted = Py_True;
2453+
}
2454+
else if (it->it_index >= PyList_GET_SIZE(seq)) {
2455+
Py_DECREF(seq);
2456+
it->it_seq = NULL;
24522457
exhausted = Py_True;
24532458
}
24542459
else {
@@ -2499,7 +2504,12 @@ dummy_func(
24992504
_PyTupleIterObject *it = (_PyTupleIterObject *)iter;
25002505
assert(Py_TYPE(iter) == &PyTupleIter_Type);
25012506
PyTupleObject *seq = it->it_seq;
2502-
if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) {
2507+
if (seq == NULL) {
2508+
exhausted = Py_True;
2509+
}
2510+
else if (it->it_index >= PyTuple_GET_SIZE(seq)) {
2511+
Py_DECREF(seq);
2512+
it->it_seq = NULL;
25032513
exhausted = Py_True;
25042514
}
25052515
else {

Python/executor_cases.c.h

+12-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)