Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return in LEAVE misses handler in directly surounding scope #1784

Open
patrickbkr opened this issue Jan 15, 2024 · 3 comments · May be fixed by #1785
Open

return in LEAVE misses handler in directly surounding scope #1784

patrickbkr opened this issue Jan 15, 2024 · 3 comments · May be fixed by #1785

Comments

@patrickbkr
Copy link
Member

sub s() {
    LEAVE return 5;
    return 7;
}
s()

gives

Attempt to return outside of any Routine
in sub s at leave-bug.raku line 2
in block at leave-bug.raku line 5

I've dug into this a bit.
From what I've understood, the return 7 starts an unwind. The exit handler of s() is found and called via MVM_frame_dispatch_from_c. That in turn sets cur_frame->return_address to *(tc->interp_cur_op) which still points to someplace in &return. The return 5 then searches for an applicable handler in the call stack, but misses the one of s() because cur_frame->return_address is then usually outside of the handlers corresponding area.

The best idea I could come up with to fix this is setting a sane cur_frame->return_address before calling the exit handler. But I don't know what a sane value could be. The value will not be used to return to (we already have a handler we are unwinding to), but needs to meet pc >= fh->start_offset && pc <= fh->end_offset (that's in exceptions.c search_frame_handlers_lex). I think the LEAVE doesn't even have a representation in the bytecode.

Hm. It's hacky, but something like the following could do the trick:

if (cur_frame == fh->frame) {
    cur_frame->return_address = fh->start_offset;
}

I do hope for a better idea though.

patrickbkr added a commit to patrickbkr/MoarVM that referenced this issue Jan 16, 2024
When a LEAVE phaser is run during an unwind, there is no valid
return_address set in the LEAVE phasers caller frame. (It return_address is
actually set to cur_op which is still the one that started the unwind in
some unrelated frame.) Thus when a `return` in a LEAVE happens, the
handler of the outer frame is missed, because `search_frame_handlers_lex()`
validates that the `return_address` lies in the handlers area. Luckily
there is a flag set on the LEAVE's outer frame:
MVM_FRAME_FLAG_EXIT_HAND_RUN. We can simply check for that flag and ignore
the frame handlers area. This is fine to do, because frames that have an
exit handler attached can not be inlined. This fixes:

    sub s() {
        LEAVE return 5;
        return 7;
    }
    s()

which before this fix printed

    Attempt to return outside of any Routine
    in sub s at leave-bug.raku line 2
    in block at leave-bug.raku line 5

Fixes MoarVM#1784
@patrickbkr patrickbkr linked a pull request Jan 16, 2024 that will close this issue
@lizmat
Copy link
Contributor

lizmat commented Jan 16, 2024

Is this PR obsolete now?

@patrickbkr
Copy link
Member Author

@lizmat This is an issue, not a PR. ;-)

@lizmat
Copy link
Contributor

lizmat commented Jan 16, 2024

Duh :-)

patrickbkr added a commit to patrickbkr/MoarVM that referenced this issue May 28, 2024
When a LEAVE phaser is run during an unwind, there is no valid
return_address set in the LEAVE phasers outer frame. (It's return_address is
actually set to interp_cur_op which is still the one that started the unwind
in some unrelated frame.) Thus when a `return` in a LEAVE happens, the
handler of the outer frame is missed, because `search_frame_handlers_lex()`
validates that the `return_address` lies in the handlers area. Luckily
there is a flag set on the LEAVE's outer frame:
MVM_FRAME_FLAG_EXIT_HAND_RUN. We can simply check for that flag and ignore
the frame handlers area. This is fine to do, because frames that have an
exit handler attached can not be inlined. This fixes:

    sub s() {
        LEAVE return 5;
        return 7;
    }
    s()

which before this fix printed

    Attempt to return outside of any Routine
    in sub s at leave-bug.raku line 2
    in block at leave-bug.raku line 5

Fixes MoarVM#1784
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants