diff --git a/bootstraptest/test_ujit.rb b/bootstraptest/test_ujit.rb index 65e20fa11748a4..318d07c6703d7f 100644 --- a/bootstraptest/test_ujit.rb +++ b/bootstraptest/test_ujit.rb @@ -177,3 +177,23 @@ def itself self end } + +# Test that getinstancevariable codegen checks for extended table size +assert_equal "nil\n", %q{ + class A + def read + @ins1000 + end + end + + ins = A.new + other = A.new + 10.times { other.instance_variable_set(:"@otr#{_1}", 'value') } + 1001.times { ins.instance_variable_set(:"@ins#{_1}", 'value') } + + ins.read + ins.read + ins.read + + p other.read +} diff --git a/ujit_codegen.c b/ujit_codegen.c index c2e534f346b542..47a05df4252cad 100644 --- a/ujit_codegen.c +++ b/ujit_codegen.c @@ -525,6 +525,15 @@ gen_getinstancevariable(jitstate_t* jit, ctx_t* ctx) test(cb, flags_opnd, imm_opnd(ROBJECT_EMBED)); jnz_ptr(cb, side_exit); + // check that the extended table is big enough + if (ivar_index >= ROBJECT_EMBED_LEN_MAX + 1) + { + // Check that the slot is inside the extended table (num_slots > index) + x86opnd_t num_slots = mem_opnd(32, REG0, offsetof(struct RObject, as.heap.numiv)); + cmp(cb, num_slots, imm_opnd(ivar_index)); + jle_ptr(cb, side_exit); + } + // Get a pointer to the extended table x86opnd_t tbl_opnd = mem_opnd(64, REG0, offsetof(struct RObject, as.heap.ivptr)); mov(cb, REG0, tbl_opnd);