summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2025-09-23 16:20:04 -0400
committerGitHub <noreply@github.com>2025-09-23 16:20:04 -0400
commit06b7a70837d831b8628ae2adde9318371c111d82 (patch)
treecd0826c747f6f8dc2b8a856fa9064fe3dd3a0c9f
parent39d764ed800fa6c930ff23067de323fd2fde4c2a (diff)
Fix thread_profile_frames crashing due to uninitialized PC
ZJIT never sets `cfp->jit_return`, so to avoid crashing while profiling, we need to explicitly validate the PC of the top most frame. Particularly pertinent for profilers that call rb_profile_frames() from within a signal handler such as Vernier and Stackprof since they can sample at any time and observe an invalid PC.
-rw-r--r--vm_backtrace.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/vm_backtrace.c b/vm_backtrace.c
index aaa0b5051c..e81c568dda 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -1761,15 +1761,22 @@ thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *b
}
if (lines) {
- // The topmost frame may not have an updated PC because the JIT
- // may not have set one. The JIT compiler will update the PC
- // before entering a new function (so that `caller` will work),
- // so only the topmost frame could possibly have an out of date PC
- if (cfp == top && cfp->jit_return) {
+ const VALUE *pc = cfp->pc;
+ VALUE *iseq_encoded = ISEQ_BODY(cfp->iseq)->iseq_encoded;
+ VALUE *pc_end = iseq_encoded + ISEQ_BODY(cfp->iseq)->iseq_size;
+
+ // The topmost frame may have an invalid PC because the JIT
+ // may leave it uninitialized for speed. JIT code must update the PC
+ // before entering a non-leaf method (so that `caller` will work),
+ // so only the topmost frame could possibly have an out-of-date PC.
+ // ZJIT doesn't set `cfp->jit_return`, so it's not a reliable signal.
+ //
+ // Avoid passing invalid PC to calc_lineno() to avoid crashing.
+ if (cfp == top && (pc < iseq_encoded || pc > pc_end)) {
lines[i] = 0;
}
else {
- lines[i] = calc_lineno(cfp->iseq, cfp->pc);
+ lines[i] = calc_lineno(cfp->iseq, pc);
}
}