Thanks to visit codestin.com
Credit goes to github.com

Skip to content

YJIT: Fix potential infinite loop when OOM (GH-13186) #13193

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

Merged
merged 1 commit into from
Apr 28, 2025

Conversation

XrXr
Copy link
Member

@XrXr XrXr commented Apr 28, 2025

Avoid generating an infinite loop in the case where:

  1. Block first is adjacent to block second, and the branch from first to
    second is a fallthrough, and
  2. Block second immediately exits to the interpreter, and
  3. Block second is invalidated and YJIT is OOM

While pondering how to fix this, I think I've stumbled on another related edge case:

  1. Block incoming_one and incoming_two both branch to block second. Block
    incoming_one has a fallthrough
  2. Block second immediately exits to the interpreter (so it starts with its exit)
  3. When Block second is invalidated, the incoming fallthrough branch from
    incoming_one might be rewritten first, which overwrites the start of block
    second with a jump to a new branch stub.
  4. YJIT runs of out memory
  5. The incoming branch from incoming_two is then rewritten, but because we're
    OOM we can't generate a new stub, so we use second's exit as the branch
    target. However second's exit was already overwritten with a jump to the
    branch stub for incoming_one, so incoming_two will end up jumping to
    incoming_one's branch stub.

Backport [Bug #21257]

Avoid generating an infinite loop in the case where:
1. Block `first` is adjacent to block `second`, and the branch from `first` to
   `second` is a fallthrough, and
2. Block `second` immediately exits to the interpreter, and
3. Block `second` is invalidated and YJIT is OOM

While pondering how to fix this, I think I've stumbled on another related edge case:
1. Block `incoming_one` and `incoming_two` both branch to block `second`. Block
   `incoming_one` has a fallthrough
2. Block `second` immediately exits to the interpreter (so it starts with its exit)
3. When Block `second` is invalidated, the incoming fallthrough branch from
   `incoming_one` might be rewritten first, which overwrites the start of block
   `second` with a jump to a new branch stub.
4. YJIT runs of out memory
5. The incoming branch from `incoming_two` is then rewritten, but because we're
   OOM we can't generate a new stub, so we use `second`'s exit as the branch
   target. However `second`'s exit was already overwritten with a jump to the
   branch stub for `incoming_one`, so `incoming_two` will end up jumping to
   `incoming_one`'s branch stub.

Backport [Bug #21257]
@XrXr
Copy link
Member Author

XrXr commented Apr 28, 2025

Looks like YJIT jobs aren't running because the Ubuntu version on Action is too old. And the segv on non-YJIT job is unrelated to this YJIT-only change.

@XrXr XrXr marked this pull request as ready for review April 28, 2025 14:24
@XrXr XrXr requested a review from k0kubun as a code owner April 28, 2025 14:24
@k0kubun k0kubun merged commit 50b1759 into ruby:ruby_3_4 Apr 28, 2025
58 of 78 checks passed
@k0kubun k0kubun deleted the 34backport-yjit-invalidation-loop branch April 28, 2025 16:23
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 this pull request may close these issues.

3 participants