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

YJIT: Fix false object collection when setting ivar #7718

Merged
merged 3 commits into from Apr 14, 2023

Conversation

XrXr
Copy link
Member

@XrXr XrXr commented Apr 14, 2023

Previously, setinstancevariable could generate code that calls
rb_ensure_iv_list_size() without first updating cfp->sp. This means
in the event that a GC start from within said routine the top few
objects would not be marked, causing them to be falsly collected.

Call jit_prepare_routine_call() first.

[Bug #19601]

@matzbot matzbot requested a review from a team April 14, 2023 19:39
yjit/src/codegen.rs Outdated Show resolved Hide resolved
@XrXr XrXr force-pushed the yjit-shape-trans-prep-ccall branch 2 times, most recently from 294adde to b8c5682 Compare April 14, 2023 20:13
@k0kubun
Copy link
Member

k0kubun commented Apr 14, 2023

Not for this PR, but with this amount of jit_prepare_routine_call, we might be calling jit_save_pc multiple times for a single instruction. I guess we should have a PC offset-like concept in JITState and skip jit_save_pc when it's been already written.

@XrXr
Copy link
Member Author

XrXr commented Apr 14, 2023

Uh oh, the regression test is so good that it crashes RJIT even after my fix attempt at f889a96. Will need to debug that further, or skip it for now for RJIT?

@k0kubun
Copy link
Member

k0kubun commented Apr 14, 2023

No worries. Please skip it for RJIT for now.

XrXr and others added 3 commits April 14, 2023 17:11
Previously, setinstancevariable could generate code that calls
`rb_ensure_iv_list_size()` without first updating `cfp->sp`. This means
in the event that a GC start from within said routine the top few
objects would not be marked, causing them to be falsly collected.

Call `jit_prepare_routine_call()` first.

[Bug #19601]
`jit_prepare_routine_call()` calls it, and there is another call above on line 2302.

Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
Despite applying a fix to RJIT similar to the YJIT fix, this test still
crashes RJIT.
@XrXr XrXr force-pushed the yjit-shape-trans-prep-ccall branch from 08ca563 to 237f738 Compare April 14, 2023 21:11
@XrXr XrXr merged commit 87c7de5 into ruby:master Apr 14, 2023
97 checks passed
@XrXr
Copy link
Member Author

XrXr commented Apr 14, 2023

Not for this PR, but with this amount of jit_prepare_routine_call, we might be calling jit_save_pc multiple times for a single instruction. I guess we should have a PC offset-like concept in JITState and skip jit_save_pc when it's been already written.

Yeah. Kind of related to that, given how often we've had this class of bugs, I think ccall should do jit_prepare_routine_call by default. Should be a much safer default, since calling without prepping requires carefully checking the called routine. It's not trivial to change the default right now because the assembler doesn't have enough info to schedule the cfp updates correctly, but maybe in the future. When it can do that, it can elide duplicate PC updates, too.

@XrXr XrXr deleted the yjit-shape-trans-prep-ccall branch April 14, 2023 22:01
@k0kubun
Copy link
Member

k0kubun commented Apr 14, 2023

If it doesn't cause a significant performance drawback, that'd be nice.

I think ccall should do jit_prepare_routine_call by default.

asm.ccall currently doesn't take JITState, which is required for jit_prepare_routine_call. Instead of adding a JITState parameter to it, another approach could be to just assert that sp_offset is 0 and local types have been cleared, which is now possible thanks to Assembler owning Context. It could still leave a stale PC, but it would still catch a missing jit_prepare_routine_call in most cases.

@maximecb
Copy link
Contributor

asm.ccall currently doesn't take JITState, which is required for jit_prepare_routine_call. Instead of adding a JITState parameter to it, another approach could be to just assert that sp_offset is 0 and local types have been cleared, which is now possible thanks to Assembler owning Context. It could still leave a stale PC, but it would still catch a missing jit_prepare_routine_call in most cases.

Seems like a decent solution.

Another option could be to remove the ccall method from assembler, and make it a method in JITState instead.

casperisfine pushed a commit to Shopify/ruby-definitions that referenced this pull request Aug 31, 2023
Backports: ruby/ruby#7718

This fixes a GC crash caused by YJIT. It generally manifest itself
with a `[BUG] try to mark T_NONE object`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants