← All issues

[22] [JSC] Move FTL stack overflow check to prologue

Severity: Medium | Component: JSC FTL JIT | 1b42291

Rated Medium because the diff fixes a JIT prologue-state invariant: the stack-overflow late path popped callee-saves but never restored SP before jumping to ThrowStackOverflowAtPrologue, so the throw thunk ran with SP pointing inside a partially-constructed frame.

The stack overflow patchpoint ran inside the lowered function body — AFTER emitFunctionPrologue, frame allocation, and callee-save spilling — and tried to undo state before jumping to a thunk that expects "at prologue" stack shape.

Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

+ Ref<B3::Air::PrologueGenerator> mainPrologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>(
+ [=](CCallHelpers& jit, B3::Air::Code& code) {
+ jit.emitFunctionPrologue();
+ // Stack overflow check before frame allocation; SP == FP, no callee-saves saved.
+ ...
+ auto stackOverflow = jit.branchPtr(...);
+ stackOverflow.linkThunk(...ThrowStackOverflowAtPrologue...);
+ if (ftlFrameSize)
+ jit.subPtr(CCallHelpers::TrustedImm32(ftlFrameSize), CCallHelpers::stackPointerRegister);
+ jit.emitSave(code.calleeSaveRegisterAtOffsetList());
+ });
+ m_proc.code().setPrologueForEntrypoint(0, WTF::move(mainPrologueGenerator));

Stack-pointer state divergence at a JIT exception edge: an out-of-line thunk was reached from a point that had advanced past the prologue without symmetrically unwinding SP.

The original code carried a FIXME pointing at the very bug number this commit closes — the author knew the stack-check belonged in the Air prologue and that the late-path emitRestore was a workaround.

🔒

The stack-pointer state at JIT exception edges, and what an off-by-one prologue invariant means for the throw path

Subscribe to read more

🔒

Several reusable audit patterns identified for late-path/thunk symmetry across JIT tiers, with concrete starting points for variant discovery

Subscribe to read more