A forward jump over a large branch body panics at runtime because the jump displacement is written with a u16 bound check but decoded as an i16.
Minimal reproduction (no and/or needed - plain if):
>> if (false()) then (count([ ...13000 members... ]) = 999) else false()
thread 'main' panicked: index out of bounds
The then branch here compiles to more than 32KB of bytecode. FunctionBuilder::patch_jump checks the offset against u16::MAX and writes two little-endian bytes, but Instruction::Jump/JumpIfTrue/JumpIfFalse hold an i16 and the VM decodes with i16::from_le_bytes, so an offset in 32768..=65535 wraps to a negative displacement and the VM jumps backward past the start of the chunk. An offset above 65535 hits the panic!("jump too far") in patch_jump instead of returning an error.
This affects every construct that emits a forward jump over a branch: if/then/else, quantified expressions, xsl:iterate, and so on. It is reachable from any sufficiently large (but not deeply nested) branch body.
I have a fix that widens the jump displacement to i32.
-Tony Bufort
A forward jump over a large branch body panics at runtime because the jump displacement is written with a
u16bound check but decoded as ani16.Minimal reproduction (no
and/orneeded - plainif):The
thenbranch here compiles to more than 32KB of bytecode.FunctionBuilder::patch_jumpchecks the offset againstu16::MAXand writes two little-endian bytes, butInstruction::Jump/JumpIfTrue/JumpIfFalsehold ani16and the VM decodes withi16::from_le_bytes, so an offset in 32768..=65535 wraps to a negative displacement and the VM jumps backward past the start of the chunk. An offset above 65535 hits thepanic!("jump too far")inpatch_jumpinstead of returning an error.This affects every construct that emits a forward jump over a branch:
if/then/else, quantified expressions,xsl:iterate, and so on. It is reachable from any sufficiently large (but not deeply nested) branch body.I have a fix that widens the jump displacement to
i32.-Tony Bufort