diff options
author | Alan Wu <[email protected]> | 2024-04-22 14:33:34 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2024-04-22 18:33:34 +0000 |
commit | aeb08bc8a71006b63a6588ef5129b7723c8219fc (patch) | |
tree | 2563b237cc301900a55ad63c0d251923c33198af /object.c | |
parent | 1bb7638e7a864db9b635c5d41f18653e8451dbc7 (diff) |
YJIT: Fix String#setbyte crashing for converted arguments
Previously, passing objects that respond to #to_int to `String#setbyte`
resulted in a crash when compiled by YJIT. This was due to the lazily
pushed frame from rb_yjit_lazy_push_frame() lingering and not being
popped by an exception as expected.
The fix is to ensure that `ec->cfp` is restored to before the lazy frame
push in case the method call for conversion succeeds. Right now, this is
only for conversion to integers.
Found running `ruby/spec`.
* clarify comment
We just need to make sure `ec->cfp` is always preserved and this can
convert without rising when `raise` is true.
Diffstat (limited to 'object.c')
-rw-r--r-- | object.c | 9 |
1 files changed, 8 insertions, 1 deletions
@@ -3236,15 +3236,22 @@ ALWAYS_INLINE(static VALUE rb_to_integer_with_id_exception(VALUE val, const char static inline VALUE rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise) { + // We need to pop the lazily pushed frame when not raising an exception. + rb_control_frame_t *current_cfp; VALUE v; if (RB_INTEGER_TYPE_P(val)) return val; + current_cfp = GET_EC()->cfp; rb_yjit_lazy_push_frame(GET_EC()->cfp->pc); v = try_to_int(val, mid, raise); - if (!raise && NIL_P(v)) return Qnil; + if (!raise && NIL_P(v)) { + GET_EC()->cfp = current_cfp; + return Qnil; + } if (!RB_INTEGER_TYPE_P(v)) { conversion_mismatch(val, "Integer", method, v); } + GET_EC()->cfp = current_cfp; return v; } #define rb_to_integer(val, method, mid) \ |