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.
This commit is contained in:
Alan Wu 2024-04-22 14:33:34 -04:00 коммит произвёл GitHub
Родитель 1bb7638e7a
Коммит aeb08bc8a7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 25 добавлений и 1 удалений

Просмотреть файл

@ -4799,3 +4799,20 @@ assert_equal [0x80000000000, 'a+', :ok].inspect, %q{
tests
}
# test String#stebyte with arguments that need conversion
assert_equal "abc", %q{
str = +"a00"
def change_bytes(str, one, two)
str.setbyte(one, "b".ord)
str.setbyte(2, two)
end
to_int_1 = Object.new
to_int_99 = Object.new
def to_int_1.to_int = 1
def to_int_99.to_int = 99
change_bytes(str, to_int_1, to_int_99)
str
}

Просмотреть файл

@ -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) \