Skip to content

Commit 9f4aac2

Browse files
committed
ZJIT: Guard that an array is not frozen before modifying it
ArrayPush calls out to the fast-path, not checking for frozen-ness. In debug mode, this leads to crashes. In release mode, silent erroneous modifications.
1 parent bdb3b1d commit 9f4aac2

4 files changed

Lines changed: 16 additions & 2 deletions

File tree

zjit/src/cruby_methods.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ fn inline_array_push(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
397397
if let &[val] = args {
398398
if !fun.likely_a(recv, types::Array, state) { return None; }
399399
let recv = fun.coerce_to(block, recv, types::Array, state);
400+
fun.guard_not_frozen(block, recv, state);
400401
let _ = fun.push_insn(block, hir::Insn::ArrayPush { array: recv, val, state });
401402
return Some(recv);
402403
}

zjit/src/hir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7273,6 +7273,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
72737273
let count = get_arg(pc, 0).as_usize();
72747274
let vals = state.stack_pop_n(count)?;
72757275
let array = state.stack_pop()?;
7276+
fun.guard_not_frozen(block, array, exit_id);
72767277
for val in vals.into_iter() {
72777278
fun.push_insn(block, Insn::ArrayPush { array, val, state: exit_id });
72787279
}

zjit/src/hir/opt_tests.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9498,6 +9498,8 @@ mod hir_opt_tests {
94989498
PatchPoint NoSingletonClass(Array@0x1008)
94999499
PatchPoint MethodRedefined(Array@0x1008, <<@0x1010, cme:0x1018)
95009500
v27:ArrayExact = GuardType v10, ArrayExact
9501+
v28:CUInt64 = LoadField v27, :_rbasic_flags@0x1040
9502+
v29:CUInt64 = GuardNoBitsSet v28, RUBY_FL_FREEZE=CUInt64(2048)
95019503
ArrayPush v27, v15
95029504
CheckInterrupts
95039505
Return v27
@@ -9530,6 +9532,8 @@ mod hir_opt_tests {
95309532
PatchPoint NoSingletonClass(Array@0x1008)
95319533
PatchPoint MethodRedefined(Array@0x1008, push@0x1010, cme:0x1018)
95329534
v26:ArrayExact = GuardType v10, ArrayExact
9535+
v27:CUInt64 = LoadField v26, :_rbasic_flags@0x1040
9536+
v28:CUInt64 = GuardNoBitsSet v27, RUBY_FL_FREEZE=CUInt64(2048)
95339537
ArrayPush v26, v15
95349538
CheckInterrupts
95359539
Return v26
@@ -9600,6 +9604,8 @@ mod hir_opt_tests {
96009604
v26:RubyValue = LoadField v23, :_ep_specval@0x1050
96019605
v27:FalseClass = GuardBitEquals v26, Value(false)
96029606
v28:Array = GuardType v9, Array
9607+
v29:CUInt64 = LoadField v28, :_rbasic_flags@0x1051
9608+
v30:CUInt64 = GuardNoBitsSet v29, RUBY_FL_FREEZE=CUInt64(2048)
96039609
ArrayPush v28, v10
96049610
CheckInterrupts
96059611
Return v28

zjit/src/hir/tests.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,10 +2405,12 @@ pub(crate) mod hir_build_tests {
24052405
bb3(v9:BasicObject, v10:BasicObject):
24062406
v16:ArrayExact = ToNewArray v10
24072407
v18:Fixnum[1] = Const Value(1)
2408+
v20:CUInt64 = LoadField v16, :_rbasic_flags@0x1001
2409+
v21:CUInt64 = GuardNoBitsSet v20, RUBY_FL_FREEZE=CUInt64(2048)
24082410
ArrayPush v16, v18
2409-
v22:BasicObject = Send v9, :foo, v16 # SendFallbackReason: Uncategorized(opt_send_without_block)
2411+
v24:BasicObject = Send v9, :foo, v16 # SendFallbackReason: Uncategorized(opt_send_without_block)
24102412
CheckInterrupts
2411-
Return v22
2413+
Return v24
24122414
");
24132415
}
24142416

@@ -4005,6 +4007,8 @@ pub(crate) mod hir_build_tests {
40054007
bb3(v9:BasicObject, v10:BasicObject):
40064008
v15:ArrayExact = ToNewArray v10
40074009
v17:Fixnum[1] = Const Value(1)
4010+
v19:CUInt64 = LoadField v15, :_rbasic_flags@0x1001
4011+
v20:CUInt64 = GuardNoBitsSet v19, RUBY_FL_FREEZE=CUInt64(2048)
40084012
ArrayPush v15, v17
40094013
CheckInterrupts
40104014
Return v15
@@ -4035,6 +4039,8 @@ pub(crate) mod hir_build_tests {
40354039
v17:Fixnum[1] = Const Value(1)
40364040
v19:Fixnum[2] = Const Value(2)
40374041
v21:Fixnum[3] = Const Value(3)
4042+
v23:CUInt64 = LoadField v15, :_rbasic_flags@0x1001
4043+
v24:CUInt64 = GuardNoBitsSet v23, RUBY_FL_FREEZE=CUInt64(2048)
40384044
ArrayPush v15, v17
40394045
ArrayPush v15, v19
40404046
ArrayPush v15, v21

0 commit comments

Comments
 (0)