Skip to content

Commit 85146a5

Browse files
authored
ZJIT: Use CFP_PC in warn_unused_block for outlined PC (ruby#16649)
warn_unused_block uses the caller's PC to build a dedup key for the unused block warning table. When called from ZJIT-compiled code via rb_vm_send, cfp->pc may be stale (poisoned or uninitialized) because ZJIT stores the real PC in cfp->jit_return instead. Use CFP_PC() which reads from jit_return when available, falling back to cfp->pc for interpreter frames. This prevents the dedup key from being based on a garbage PC value that could randomly collide with prior entries, suppressing warnings that should be emitted.
1 parent e957b3a commit 85146a5

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

vm_insnhelper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3219,7 +3219,7 @@ vm_callee_setup_arg(rb_execution_context_t *ec, struct rb_calling_info *calling,
32193219
if (UNLIKELY(!ISEQ_BODY(iseq)->param.flags.use_block &&
32203220
calling->block_handler != VM_BLOCK_HANDLER_NONE &&
32213221
!(vm_ci_flag(calling->cd->ci) & (VM_CALL_OPT_SEND | VM_CALL_SUPER)))) {
3222-
warn_unused_block(vm_cc_cme(cc), iseq, (void *)ec->cfp->pc);
3222+
warn_unused_block(vm_cc_cme(cc), iseq, (void *)CFP_PC(ec->cfp));
32233223
}
32243224

32253225
if (LIKELY(!(vm_ci_flag(ci) & VM_CALL_KW_SPLAT))) {

zjit/src/codegen_tests.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5544,3 +5544,30 @@ fn test_send_block_to_method_not_using_block() {
55445544
test
55455545
"), @"42");
55465546
}
5547+
5548+
#[test]
5549+
fn test_send_block_unused_warning_emitted_from_jit() {
5550+
// When ZJIT compiles a send with a block as a dynamic dispatch fallback
5551+
// (gen_send -> rb_vm_send), warn_unused_block uses cfp->pc for the dedup
5552+
// key. We save cfp->pc before calling rb_vm_send so the key is stable
5553+
// and won't spuriously collide with prior entries in the dedup table.
5554+
assert_snapshot!(inspect(r#"
5555+
$warnings = []
5556+
module Warning
5557+
def warn(message, category: nil)
5558+
$warnings << message
5559+
end
5560+
end
5561+
5562+
def m_unused_block_warn_test = 42
5563+
5564+
def test
5565+
$VERBOSE = true
5566+
m_unused_block_warn_test {}
5567+
$warnings.any? { |w| w.include?("may be ignored") }
5568+
end
5569+
5570+
test
5571+
test
5572+
"#), @"true");
5573+
}

0 commit comments

Comments
 (0)