Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitefb8a25

Browse files
authored
GH-103488: Use return-offset, not yield-offset. (GH-103502)
* Use return-offset, not yield-offset, so that instruction pointer is correct when sending to a generator or coroutine.
1 parent4307fea commitefb8a25

File tree

6 files changed

+455
-414
lines changed

6 files changed

+455
-414
lines changed

‎Include/internal/pycore_frame.h‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ typedef struct _PyInterpreterFrame {
6161
// over, or (in the case of a newly-created frame) a totally invalid value:
6262
_Py_CODEUNIT*prev_instr;
6363
intstacktop;/* Offset of TOS from localsplus */
64-
uint16_tyield_offset;
64+
/* The return_offset determines where a `RETURN` should go in the caller,
65+
* relative to `prev_instr`.
66+
* It is only meaningful to the callee,
67+
* so it needs to be set in any CALL (to a Python function)
68+
* or SEND (to a coroutine or generator).
69+
* If there is no callee, then it is meaningless. */
70+
uint16_treturn_offset;
6571
charowner;
6672
/* Locals and stack */
6773
PyObject*localsplus[1];
@@ -121,7 +127,7 @@ _PyFrame_Initialize(
121127
frame->stacktop=code->co_nlocalsplus;
122128
frame->frame_obj=NULL;
123129
frame->prev_instr=_PyCode_CODE(code)-1;
124-
frame->yield_offset=0;
130+
frame->return_offset=0;
125131
frame->owner=FRAME_OWNED_BY_THREAD;
126132

127133
for (inti=null_locals_from;i<code->co_nlocalsplus;i++) {

‎Lib/test/test_generators.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,22 @@ def f():
225225
gi=f()
226226
self.assertIsNone(gi.gi_frame.f_back)
227227

228+
deftest_issue103488(self):
228229

230+
defgen_raises():
231+
yield
232+
raiseValueError()
233+
234+
defloop():
235+
try:
236+
for_ingen_raises():
237+
ifTrueisFalse:
238+
return
239+
exceptValueError:
240+
pass
241+
242+
#This should not raise
243+
loop()
229244

230245
classExceptionTest(unittest.TestCase):
231246
# Tests for the issue #23353: check that the currently handled exception
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Change the internal offset distinguishing yield and return target addresses,
2+
so that the instruction pointer is correct for exception handling and other
3+
stack unwinding.

‎Python/bytecodes.c‎

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ dummy_func(
506506
new_frame->localsplus[0]=container;
507507
new_frame->localsplus[1]=sub;
508508
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
509+
frame->return_offset=0;
509510
DISPATCH_INLINED(new_frame);
510511
}
511512

@@ -637,6 +638,7 @@ dummy_func(
637638
_PyInterpreterFrame*dying=frame;
638639
frame=cframe.current_frame=dying->previous;
639640
_PyEvalFrameClearAndPop(tstate,dying);
641+
frame->prev_instr+=frame->return_offset;
640642
_PyFrame_StackPush(frame,retval);
641643
gotoresume_frame;
642644
}
@@ -655,6 +657,7 @@ dummy_func(
655657
_PyInterpreterFrame*dying=frame;
656658
frame=cframe.current_frame=dying->previous;
657659
_PyEvalFrameClearAndPop(tstate,dying);
660+
frame->prev_instr+=frame->return_offset;
658661
_PyFrame_StackPush(frame,retval);
659662
gotoresume_frame;
660663
}
@@ -670,6 +673,7 @@ dummy_func(
670673
_PyInterpreterFrame*dying=frame;
671674
frame=cframe.current_frame=dying->previous;
672675
_PyEvalFrameClearAndPop(tstate,dying);
676+
frame->prev_instr+=frame->return_offset;
673677
_PyFrame_StackPush(frame,retval);
674678
gotoresume_frame;
675679
}
@@ -689,6 +693,7 @@ dummy_func(
689693
_PyInterpreterFrame*dying=frame;
690694
frame=cframe.current_frame=dying->previous;
691695
_PyEvalFrameClearAndPop(tstate,dying);
696+
frame->prev_instr+=frame->return_offset;
692697
_PyFrame_StackPush(frame,retval);
693698
gotoresume_frame;
694699
}
@@ -823,13 +828,13 @@ dummy_func(
823828
{
824829
PyGenObject*gen= (PyGenObject*)receiver;
825830
_PyInterpreterFrame*gen_frame= (_PyInterpreterFrame*)gen->gi_iframe;
826-
frame->yield_offset=oparg;
831+
frame->return_offset=oparg;
827832
STACK_SHRINK(1);
828833
_PyFrame_StackPush(gen_frame,v);
829834
gen->gi_frame_state=FRAME_EXECUTING;
830835
gen->gi_exc_state.previous_item=tstate->exc_info;
831836
tstate->exc_info=&gen->gi_exc_state;
832-
JUMPBY(INLINE_CACHE_ENTRIES_SEND+oparg);
837+
JUMPBY(INLINE_CACHE_ENTRIES_SEND);
833838
DISPATCH_INLINED(gen_frame);
834839
}
835840
if (Py_IsNone(v)&&PyIter_Check(receiver)) {
@@ -861,13 +866,13 @@ dummy_func(
861866
DEOPT_IF(gen->gi_frame_state >=FRAME_EXECUTING,SEND);
862867
STAT_INC(SEND,hit);
863868
_PyInterpreterFrame*gen_frame= (_PyInterpreterFrame*)gen->gi_iframe;
864-
frame->yield_offset=oparg;
869+
frame->return_offset=oparg;
865870
STACK_SHRINK(1);
866871
_PyFrame_StackPush(gen_frame,v);
867872
gen->gi_frame_state=FRAME_EXECUTING;
868873
gen->gi_exc_state.previous_item=tstate->exc_info;
869874
tstate->exc_info=&gen->gi_exc_state;
870-
JUMPBY(INLINE_CACHE_ENTRIES_SEND+oparg);
875+
JUMPBY(INLINE_CACHE_ENTRIES_SEND);
871876
DISPATCH_INLINED(gen_frame);
872877
}
873878

@@ -886,7 +891,6 @@ dummy_func(
886891
_PyInterpreterFrame*gen_frame=frame;
887892
frame=cframe.current_frame=frame->previous;
888893
gen_frame->previous=NULL;
889-
frame->prev_instr-=frame->yield_offset;
890894
_PyFrame_StackPush(frame,retval);
891895
gotoresume_frame;
892896
}
@@ -905,7 +909,6 @@ dummy_func(
905909
_PyInterpreterFrame*gen_frame=frame;
906910
frame=cframe.current_frame=frame->previous;
907911
gen_frame->previous=NULL;
908-
frame->prev_instr-=frame->yield_offset;
909912
_PyFrame_StackPush(frame,retval);
910913
gotoresume_frame;
911914
}
@@ -1724,6 +1727,7 @@ dummy_func(
17241727
STACK_SHRINK(shrink_stack);
17251728
new_frame->localsplus[0]=owner;
17261729
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
1730+
frame->return_offset=0;
17271731
DISPATCH_INLINED(new_frame);
17281732
}
17291733

@@ -1751,6 +1755,7 @@ dummy_func(
17511755
new_frame->localsplus[0]=owner;
17521756
new_frame->localsplus[1]=Py_NewRef(name);
17531757
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
1758+
frame->return_offset=0;
17541759
DISPATCH_INLINED(new_frame);
17551760
}
17561761

@@ -2259,14 +2264,14 @@ dummy_func(
22592264
DEOPT_IF(gen->gi_frame_state >=FRAME_EXECUTING,FOR_ITER);
22602265
STAT_INC(FOR_ITER,hit);
22612266
_PyInterpreterFrame*gen_frame= (_PyInterpreterFrame*)gen->gi_iframe;
2262-
frame->yield_offset=oparg;
2267+
frame->return_offset=oparg;
22632268
_PyFrame_StackPush(gen_frame,Py_NewRef(Py_None));
22642269
gen->gi_frame_state=FRAME_EXECUTING;
22652270
gen->gi_exc_state.previous_item=tstate->exc_info;
22662271
tstate->exc_info=&gen->gi_exc_state;
2267-
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER+oparg);
2268-
assert(next_instr->op.code==END_FOR||
2269-
next_instr->op.code==INSTRUMENTED_END_FOR);
2272+
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER);
2273+
assert(next_instr[oparg].op.code==END_FOR||
2274+
next_instr[oparg].op.code==INSTRUMENTED_END_FOR);
22702275
DISPATCH_INLINED(gen_frame);
22712276
}
22722277

@@ -2521,6 +2526,7 @@ dummy_func(
25212526
gotoerror;
25222527
}
25232528
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
2529+
frame->return_offset=0;
25242530
DISPATCH_INLINED(new_frame);
25252531
}
25262532
/* Callable is not a normal Python function */
@@ -2594,6 +2600,7 @@ dummy_func(
25942600
// Manipulate stack directly since we leave using DISPATCH_INLINED().
25952601
STACK_SHRINK(oparg+2);
25962602
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
2603+
frame->return_offset=0;
25972604
DISPATCH_INLINED(new_frame);
25982605
}
25992606

@@ -2631,6 +2638,7 @@ dummy_func(
26312638
// Manipulate stack and cache directly since we leave using DISPATCH_INLINED().
26322639
STACK_SHRINK(oparg+2);
26332640
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
2641+
frame->return_offset=0;
26342642
DISPATCH_INLINED(new_frame);
26352643
}
26362644

‎Python/ceval.c‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
672672
_PyCode_CODE(tstate->interp->interpreter_trampoline);
673673
entry_frame.stacktop=0;
674674
entry_frame.owner=FRAME_OWNED_BY_CSTACK;
675-
entry_frame.yield_offset=0;
675+
entry_frame.return_offset=0;
676676
/* Push frame */
677677
entry_frame.previous=prev_cframe->current_frame;
678678
frame->previous=&entry_frame;
@@ -881,6 +881,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
881881
_PyInterpreterFrame*dying=frame;
882882
frame=cframe.current_frame=dying->previous;
883883
_PyEvalFrameClearAndPop(tstate,dying);
884+
frame->return_offset=0;
884885
if (frame==&entry_frame) {
885886
/* Restore previous cframe and exit */
886887
tstate->cframe=cframe.previous;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp