Project

General

Profile

Actions

Bug #20626

open

`defined?(@ivar)` should return nil when `@iv` can raise on Ractor

Added by ko1 (Koichi Sasada) 7 days ago. Updated 6 days ago.

Status:
Open
Target version:
-
[ruby-core:118539]

Description

Return nil for defined?(@ivar) on some cases with Ractor.

Background

It is not allowed to get instance variables from an object if

  1. the object is shareable
  2. and the instance variable refers to an unshareable object

like the following code:

class Ractor
  def setup_iv
    @iv = []
  end
  def get_iv = @iv
end

R = Ractor.new{}
R.setup_iv
p R.get_iv #=> []

Ractor.new{|;iv|
  p R.get_iv #=> can not access instance variables of shareable objects from non-main Ractors (Ractor::IsolationError)
}.take

I believe nobody use ivars on Ractor objects. However it is used on classes and modules (shareable objects) casually use it.

class C
  @iv = []
  def self.iv = @iv
end

p C.iv #=> []

Ractor.new{
  p C.iv #=> can not get unshareable values from instance variables of classes/modules from non-main Ractors (Ractor::IsolationError)
}.take

Current behavior on defined? with such ivars is strange because:

  • Case1: raising an error
class C
  @iv1 = []
  def self.defined_iv1 = defined?(@iv1)
end

Ractor.new{
  p C.defined_iv1
  #=> can not get unshareable values from instance variables of classes/modules from non-main Ractors (Ractor::IsolationError)
}.take
  • Case2: incorrect result
class C
  # @iv2 is not defined
  def self.defined_iv2 = defined?(@iv2)
end

Ractor.new{
  p C.defined_iv2 #=> "instance-variable"
}.take

This is because current implementation uses accessing ivars on such cases. It seems a simple bug.

Proposal

In other words, we can't use such ivars on Ractors on Case1.
So that returning nil on Case1 and Case2 reasonable.

class C
  @iv1 = []
  def self.defined_iv1 = defined?(@iv1)

  # @iv2 is not defined
  def self.defined_iv2 = defined?(@iv2)

  @iv3 = 42 # refers to shareable object
  def self.defined_iv2 = defined?(@iv3)
end

p C.defined_iv1 #=> "instance-variable"
p C.defined_iv2 #=> "instance-variable"

Ractor.new{
  p C.defined_iv1
   # current:  can not get unshareable values from instance variables of classes/modules from non-main Ractors (Ractor::IsolationError)
   # proposed: nil because it is not accessible from here

  p C.defined_iv2
   # current: "instance-variable"
   # proposed: nil
   
  p C.defined_iv3 #=> "instance-variable" because we can access it
}.take

Usage

FileUtils uses defined?(@non_existing_ivar) technique to configure its behavior so I found the Case2.
https://github.com/ruby/fileutils/blob/master/lib/fileutils.rb#L2501

Implementation

https://github.com/ruby/ruby/pull/11141

We need more modification to YJIT.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0