Do not read cached_id from callcache on stack

The inline cache is initialized by vm_cc_attr_index_set only when
vm_cc_markable(cc). However, vm_getivar attempted to read the cache
even if the cc is not vm_cc_markable.

This caused a condition that depends on uninitialized value.
Here is an output of valgrind:

```
==10483== Conditional jump or move depends on uninitialised value(s)
==10483==    at 0x4C1D60: vm_getivar (vm_insnhelper.c:1171)
==10483==    by 0x4C1D60: vm_call_ivar (vm_insnhelper.c:3257)
==10483==    by 0x4E8E48: vm_call_symbol (vm_insnhelper.c:3481)
==10483==    by 0x4EAD8C: vm_sendish (vm_insnhelper.c:5035)
==10483==    by 0x4C62B2: vm_exec_core (insns.def:820)
==10483==    by 0x4DD519: rb_vm_exec (vm.c:0)
==10483==    by 0x4F00B3: invoke_block (vm.c:1417)
==10483==    by 0x4F00B3: invoke_iseq_block_from_c (vm.c:1473)
==10483==    by 0x4F00B3: invoke_block_from_c_bh (vm.c:1491)
==10483==    by 0x4D42B6: rb_yield (vm_eval.c:0)
==10483==    by 0x259128: rb_ary_each (array.c:2733)
==10483==    by 0x4E8730: vm_call_cfunc_with_frame (vm_insnhelper.c:3227)
==10483==    by 0x4EAD8C: vm_sendish (vm_insnhelper.c:5035)
==10483==    by 0x4C6254: vm_exec_core (insns.def:801)
==10483==    by 0x4DD519: rb_vm_exec (vm.c:0)
==10483==
```

In fact, the CI on FreeBSD 12 started failing since ad63b668e2.

```
gmake[1]: Entering directory '/usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby'
/usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:924:in `complete': undefined method `complete' for nil:NilClass (NoMethodError)
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1816:in `block in visit'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1815:in `reverse_each'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1815:in `visit'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1847:in `block in complete'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1846:in `catch'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1846:in `complete'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1640:in `block in parse_in_order'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1632:in `catch'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1632:in `parse_in_order'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1626:in `order!'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1732:in `permute!'
	from /usr/home/chkbuild/chkbuild/tmp/build/20221011T163003Z/ruby/lib/optparse.rb:1757:in `parse!'
	from ./ext/extmk.rb:359:in `parse_args'
	from ./ext/extmk.rb:396:in `<main>'
```

This change adds a guard to read the cache only when vm_cc_markable(cc).
It might be better to initialize the cache as INVALID_SHAPE_ID when the
cc is not vm_cc_markable.
This commit is contained in:
Yusuke Endoh 2022-10-12 19:02:11 +09:00
Родитель 66a650ec41
Коммит 7a9f865a1d
2 изменённых файлов: 8 добавлений и 1 удалений

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

@ -385,6 +385,7 @@ vm_cc_attr_index_dest_shape_id(const struct rb_callcache *cc)
static inline void static inline void
vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t * shape_id, attr_index_t * index) vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t * shape_id, attr_index_t * index)
{ {
VM_ASSERT(vm_cc_markable(cc));
uintptr_t cache_value = cc->aux_.attr.value; // Atomically read 64 bits uintptr_t cache_value = cc->aux_.attr.value; // Atomically read 64 bits
*shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT); *shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT);
*index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1; *index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1;

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

@ -1160,7 +1160,13 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
attr_index_t index; attr_index_t index;
if (is_attr) { if (is_attr) {
vm_cc_atomic_shape_and_index(cc, &cached_id, &index); if (vm_cc_markable(cc)) {
vm_cc_atomic_shape_and_index(cc, &cached_id, &index);
}
else {
cached_id = INVALID_SHAPE_ID;
index = ATTR_INDEX_NOT_SET;
}
} }
else { else {
vm_ic_atomic_shape_and_index(ic, &cached_id, &index); vm_ic_atomic_shape_and_index(ic, &cached_id, &index);