[ruby-core:118170] [Ruby master Bug#20522] YJIT can panic if shape transition in `gen_setinstancevariable` emits a performance warning

Issue #20522 has been reported by byroot (Jean Boussier). ---------------------------------------- Bug #20522: YJIT can panic if shape transition in `gen_setinstancevariable` emits a performance warning https://bugs.ruby-lang.org/issues/20522 * Author: byroot (Jean Boussier) * Status: Open * ruby -v: ruby 3.3.2 (2024-05-30 revision e5a195edf6) [arm64-darwin23] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: REQUIRED ---------------------------------------- Reproduction script: ```ruby Warning[:performance] = true module StrictWarnings def warn(msg, category: nil, **) raise msg end end Warning.singleton_class.prepend(StrictWarnings) class A def compiled_method(is_private) @some_ivar = is_private end end 100.times do |i| klass = Class.new(A) 7.times do |j| obj = klass.new obj.instance_variable_set("@base_#{i}", 42) obj.instance_variable_set("@ivar_#{j}", 42) end obj = klass.new obj.instance_variable_set("@base_#{i}", 42) begin obj.compiled_method(true) rescue end end ``` ### Context `compiled_method` contains a `setinstancevariable` instruction, which when compiled by YJIT eagerly create the next shape if it doesn't already exist. If `Warning.warn` is redefined, then Ruby code may be invoked while YJIT is compiling, which is unsafe. ### Solution Performance warnings are best effort, so the simplest solution is to not emit warnings when YJIT is compiling. (patch incoming). -- https://bugs.ruby-lang.org/

Issue #20522 has been updated by byroot (Jean Boussier). Patch: https://github.com/ruby/ruby/pull/10910 ---------------------------------------- Bug #20522: YJIT can panic if shape transition in `gen_setinstancevariable` emits a performance warning https://bugs.ruby-lang.org/issues/20522#change-108616 * Author: byroot (Jean Boussier) * Status: Open * ruby -v: ruby 3.3.2 (2024-05-30 revision e5a195edf6) [arm64-darwin23] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: REQUIRED ---------------------------------------- Reproduction script: ```ruby Warning[:performance] = true module StrictWarnings def warn(msg, category: nil, **) raise msg end end Warning.singleton_class.prepend(StrictWarnings) class A def compiled_method(is_private) @some_ivar = is_private end end 100.times do |i| klass = Class.new(A) 7.times do |j| obj = klass.new obj.instance_variable_set("@base_#{i}", 42) obj.instance_variable_set("@ivar_#{j}", 42) end obj = klass.new obj.instance_variable_set("@base_#{i}", 42) begin obj.compiled_method(true) rescue end end ``` ### Context `compiled_method` contains a `setinstancevariable` instruction, which when compiled by YJIT eagerly create the next shape if it doesn't already exist. If `Warning.warn` is redefined, then Ruby code may be invoked while YJIT is compiling, which is unsafe. ### Solution Performance warnings are best effort, so the simplest solution is to not emit warnings when YJIT is compiling. (patch incoming). -- https://bugs.ruby-lang.org/

Issue #20522 has been updated by byroot (Jean Boussier). 3.3 backport PR: https://github.com/ruby/ruby/pull/10911 ---------------------------------------- Bug #20522: YJIT can panic if shape transition in `gen_setinstancevariable` emits a performance warning https://bugs.ruby-lang.org/issues/20522#change-108619 * Author: byroot (Jean Boussier) * Status: Closed * ruby -v: ruby 3.3.2 (2024-05-30 revision e5a195edf6) [arm64-darwin23] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: REQUIRED ---------------------------------------- Reproduction script: ```ruby Warning[:performance] = true module StrictWarnings def warn(msg, category: nil, **) raise msg end end Warning.singleton_class.prepend(StrictWarnings) class A def compiled_method(is_private) @some_ivar = is_private end end 100.times do |i| klass = Class.new(A) 7.times do |j| obj = klass.new obj.instance_variable_set("@base_#{i}", 42) obj.instance_variable_set("@ivar_#{j}", 42) end obj = klass.new obj.instance_variable_set("@base_#{i}", 42) begin obj.compiled_method(true) rescue end end ``` ### Context `compiled_method` contains a `setinstancevariable` instruction, which when compiled by YJIT eagerly create the next shape if it doesn't already exist. If `Warning.warn` is redefined, then Ruby code may be invoked while YJIT is compiling, which is unsafe. ### Solution Performance warnings are best effort, so the simplest solution is to not emit warnings when YJIT is compiling. (patch incoming). -- https://bugs.ruby-lang.org/

Issue #20522 has been updated by k0kubun (Takashi Kokubun). Backport changed from 3.1: DONTNEED, 3.2: DONTNEED, 3.3: REQUIRED to 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONE ruby_3_3 commit:4f00d98b327e3aa23564aa765488d15bc60c9e79. ---------------------------------------- Bug #20522: YJIT can panic if shape transition in `gen_setinstancevariable` emits a performance warning https://bugs.ruby-lang.org/issues/20522#change-108621 * Author: byroot (Jean Boussier) * Status: Closed * ruby -v: ruby 3.3.2 (2024-05-30 revision e5a195edf6) [arm64-darwin23] * Backport: 3.1: DONTNEED, 3.2: DONTNEED, 3.3: DONE ---------------------------------------- Reproduction script: ```ruby Warning[:performance] = true module StrictWarnings def warn(msg, category: nil, **) raise msg end end Warning.singleton_class.prepend(StrictWarnings) class A def compiled_method(is_private) @some_ivar = is_private end end 100.times do |i| klass = Class.new(A) 7.times do |j| obj = klass.new obj.instance_variable_set("@base_#{i}", 42) obj.instance_variable_set("@ivar_#{j}", 42) end obj = klass.new obj.instance_variable_set("@base_#{i}", 42) begin obj.compiled_method(true) rescue end end ``` ### Context `compiled_method` contains a `setinstancevariable` instruction, which when compiled by YJIT eagerly create the next shape if it doesn't already exist. If `Warning.warn` is redefined, then Ruby code may be invoked while YJIT is compiling, which is unsafe. ### Solution Performance warnings are best effort, so the simplest solution is to not emit warnings when YJIT is compiling. (patch incoming). -- https://bugs.ruby-lang.org/
participants (2)
-
byroot (Jean Boussier)
-
k0kubun (Takashi Kokubun)