Skip to content
  • Rian McGuire's avatar
    80a1a1bb
    YJIT: Fix potential infinite loop when OOM (GH-13186) · 80a1a1bb
    Rian McGuire authored
    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.
    
    Fixes [Bug #21257]
    80a1a1bb
    YJIT: Fix potential infinite loop when OOM (GH-13186)
    Rian McGuire authored
    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.
    
    Fixes [Bug #21257]
Loading