Skip to content

Commit

Permalink
YJIT: Avoid identity-based known-class guards for IO objects (#7911)
Browse files Browse the repository at this point in the history
`IO#reopen` is very special in that it is able to change the class and
singleton class of IO instances. In its presence, it is not correct to
assume that IO instances has a stable class/singleton class and guard
by comparing identity.
  • Loading branch information
XrXr committed Jun 6, 2023
1 parent 7577c10 commit 2b54c13
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 0 deletions.
12 changes: 12 additions & 0 deletions test/ruby/test_yjit.rb
Expand Up @@ -1277,6 +1277,18 @@ def foo(a, b, h)
RUBY
end

def test_io_reopen_clobbering_singleton_class
assert_compiles(<<~RUBY, result: [:ok, :ok])
def $stderr.to_i = :i
def test = $stderr.to_i
[test, test]
$stderr.reopen($stderr.dup)
[test, test].map { :ok unless _1 == :i }
RUBY
end

private

def code_gc_helpers
Expand Down
1 change: 1 addition & 0 deletions yjit/bindgen/src/main.rs
Expand Up @@ -165,6 +165,7 @@ fn main() {
.allowlist_var("rb_cTrueClass")
.allowlist_var("rb_cFalseClass")
.allowlist_var("rb_cInteger")
.allowlist_var("rb_cIO")
.allowlist_var("rb_cSymbol")
.allowlist_var("rb_cFloat")
.allowlist_var("rb_cString")
Expand Down
3 changes: 3 additions & 0 deletions yjit/src/codegen.rs
Expand Up @@ -3871,6 +3871,7 @@ fn jit_guard_known_klass(
} else if unsafe {
FL_TEST(known_klass, VALUE(RUBY_FL_SINGLETON as usize)) != VALUE(0)
&& sample_instance == rb_class_attached_object(known_klass)
&& !rb_obj_is_kind_of(sample_instance, rb_cIO).test()
} {
// Singleton classes are attached to one specific object, so we can
// avoid one memory access (and potentially the is_heap check) by
Expand All @@ -3882,6 +3883,8 @@ fn jit_guard_known_klass(
// that its singleton class is empty, so we can't avoid the memory
// access. As an example, `Object.new.singleton_class` is an object in
// this situation.
// Also, guarding by identity is incorrect for IO objects because
// IO#reopen can be used to change the class and singleton class of IO objects!
asm.comment("guard known object with singleton class");
asm.cmp(obj_opnd, sample_instance.into());
jit_chain_guard(JCC_JNE, jit, asm, ocb, max_chain_depth, counter);
Expand Down
1 change: 1 addition & 0 deletions yjit/src/cruby_bindings.inc.rs
Expand Up @@ -1083,6 +1083,7 @@ extern "C" {
pub static mut rb_cFalseClass: VALUE;
pub static mut rb_cFloat: VALUE;
pub static mut rb_cHash: VALUE;
pub static mut rb_cIO: VALUE;
pub static mut rb_cInteger: VALUE;
pub static mut rb_cModule: VALUE;
pub static mut rb_cNilClass: VALUE;
Expand Down

0 comments on commit 2b54c13

Please sign in to comment.