diff options
-rw-r--r-- | bootstraptest/test_yjit.rb | 13 | ||||
-rw-r--r-- | yjit/src/codegen.rs | 9 | ||||
-rw-r--r-- | yjit/src/invariants.rs | 11 |
3 files changed, 30 insertions, 3 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index cab905a2af..64203322c6 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -3677,3 +3677,16 @@ assert_equal "foo", %q{ literal("foo") } + +# regression test for accidentally having a parameter truncated +# due to Rust/C signature mismatch. Used to crash with +# > [BUG] rb_vm_insn_addr2insn: invalid insn address ... +# or +# > ... `Err` value: TryFromIntError(())' +assert_normal_exit %q{ + n = 16384 + eval( + "def foo(arg); " + "_=arg;" * n + '_=1;' + "Object; end" + ) + foo 1 +} diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 824415346e..fb760cfd6c 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -781,8 +781,13 @@ pub fn gen_single_block( // Instruction sequence to compile let iseq = blockid.iseq; let iseq_size = unsafe { get_iseq_encoded_size(iseq) }; - let iseq_size: u16 = iseq_size.try_into().unwrap(); - let mut insn_idx: u16 = blockid.idx; + let iseq_size: IseqIdx = if let Ok(size) = iseq_size.try_into() { + size + } else { + // ISeq too large to compile + return Err(()); + }; + let mut insn_idx: IseqIdx = blockid.idx; // Initialize a JIT state object let mut jit = JITState::new(blockid, ctx.clone(), cb.get_write_ptr(), ec); diff --git a/yjit/src/invariants.rs b/yjit/src/invariants.rs index 5156ca6a26..c93213b484 100644 --- a/yjit/src/invariants.rs +++ b/yjit/src/invariants.rs @@ -389,12 +389,21 @@ pub fn block_assumptions_free(blockref: BlockRef) { /// Invalidate the block for the matching opt_getinlinecache so it could regenerate code /// using the new value in the constant cache. #[no_mangle] -pub extern "C" fn rb_yjit_constant_ic_update(iseq: *const rb_iseq_t, ic: IC, insn_idx: u16) { +pub extern "C" fn rb_yjit_constant_ic_update(iseq: *const rb_iseq_t, ic: IC, insn_idx: std::os::raw::c_uint) { // If YJIT isn't enabled, do nothing if !yjit_enabled_p() { return; } + // Try to downcast the iseq index + let insn_idx: IseqIdx = if let Ok(idx) = insn_idx.try_into() { + idx + } else { + // The index is too large, YJIT can't possibily have code for it, + // so there is nothing to invalidate. + return; + }; + if !unsafe { (*(*ic).entry).ic_cref }.is_null() || unsafe { rb_yjit_multi_ractor_p() } { // We can't generate code in these situations, so no need to invalidate. // See gen_opt_getinlinecache. |