Project

General

Profile

Actions

Bug #2502

closed

strange behavior of anonymous class inside a proc

Added by coatl (caleb clausen) about 15 years ago. Updated over 13 years ago.

Status:
Closed
Target version:
-
ruby -v:
ruby 1.9.1p376 (2009-12-07 revision 26040 [x86_64-linux]
Backport:
[ruby-core:27230]

Description

=begin
I have a problem in 1.9.1 when I run this code, extracted from a larger project:
$VERBOSE=1

class SubSeq
def initialize
@first=11
@first or fail
end

 def subseq 
   @first or fail
 end    

end

class Indexed
def subseq
SubSeq.new
end
end

Overlaid =proc do
p self
class<<self
def subseq
super.instance_eval(& Overlaid)
end
end
end

mid=Indexed.new
mid.instance_eval(&Overlaid)
mid.subseq
p mid
mid.subseq

The output I get is like this:
#Indexed:0x000000007a8930
#<SubSeq:0x000000007a7e78 @first=11>
#Indexed:0x000000007a8930
subseq_first_nil.rb:10: warning: instance variable @first not initialized
subseq_first_nil.rb:10:in subseq': unhandled exception from subseq_first_nil.rb:24:in subseq'
from subseq_first_nil.rb:33:in `'

This code should run without raising an exception, and does in ruby 1.8. The exception is raised from within the last line, the second call to mid.subseq. Both mid.subseq calls should behave exactly the same. The first appears to do all the right things. But in the second, it goes all awry. They should both call first the anonymous class's #subseq, then (via the super) Indexed#subseq, which ultimately returns a SubSeq object, also decorated by the anonymous class. SubSeq#subseq itself should never be called, but somehow (given the top line of the exception traceback and the warning) it is. SubSeq's @first should never be nil, since it is initialized in the constructor and never changed, but somehow it is.

This is the last remaining (serious) problem in porting redparse to 1.9. It causes redparse to incorrectly handle certain here documents which work fine when run in 1.8. I'd appreciate it very much of this problem can be fixed.

I've observed this in 1.9.1, but not 1.9.2.
=end


Related issues 2 (0 open2 closed)

Related to Ruby master - Bug #3351: stack overflow on superClosedko1 (Koichi Sasada)Actions
Has duplicate Ruby master - Bug #3136: reuse of singleton method definition causes SEGVClosedko1 (Koichi Sasada)04/12/2010Actions
Actions #1

Updated by naruse (Yui NARUSE) almost 15 years ago

  • Category set to core

=begin
This also affect Ruby 1.9.
=end

Actions #2

Updated by naruse (Yui NARUSE) almost 15 years ago

  • Status changed from Open to Assigned
  • Assignee set to ko1 (Koichi Sasada)
  • Priority changed from 5 to 3

=begin

=end

Actions #3

Updated by mame (Yusuke Endoh) over 14 years ago

=begin
Hi,

2009/12/19 caleb clausen :

I have a problem in 1.9.1 when I run this code, extracted from a larger project:
$VERBOSE=1

class SubSeq
def initialize
@first=11
@first or fail
end

def subseq
@first or fail
end
end

class Indexed
def subseq
SubSeq.new
end
end

Overlaid =proc do
p self
class<<self
def subseq
super.instance_eval(& Overlaid)
end
end
end

mid=Indexed.new
mid.instance_eval(&Overlaid)
mid.subseq
p mid
mid.subseq

The output I get is like this:
#Indexed:0x000000007a8930
#<SubSeq:0x000000007a7e78 @first=11>
#Indexed:0x000000007a8930
subseq_first_nil.rb:10: warning: instance variable @first not initialized
subseq_first_nil.rb:10:in subseq': unhandled exception from subseq_first_nil.rb:24:in subseq'
from subseq_first_nil.rb:33:in `'

This code should run without raising an exception, and does in ruby 1.8. The exception is raised from within the last line, the second call to mid.subseq. Both mid.subseq calls should behave exactly the same. The first appears to do all the right things. But in the second, it goes all awry. They should both call first the anonymous class's #subseq, then (via the super) Indexed#subseq, which ultimately returns a SubSeq object, also decorated by the anonymous class. SubSeq#subseq itself should never be called, but somehow (given the top line of the exception traceback and the warning) it is. SubSeq's @first should never be nil, since it is initialized in the constructor and never changed, but somehow it is.

This is the last remaining (serious) problem in porting redparse to 1.9. It causes redparse to incorrectly handle certain here documents which work fine when run in 1.8. I'd appreciate it very much of this problem can be fixed.

Definitely, this is a bug. But it is very difficult to fix because
this is a design flaw of YARV.

Each method definition (more precisely, rb_iseq_t) has information
of class that the method belongs to. This information is used to
identify the parent class and method when super is called.

This information belongs to each lexical method definition.
Your code uses the same definition of method `subseq' twice, to an
instance of Indexed, and to an instance of SubSeq.
The first definition sets the information to Indexed, and the second
overwrites it to SubSeq. This causes inconsistency between class
of self and class that a super'ed method belongs to.

To fix this issue, the information must be moved from rb_iseq_t to
stack frame, which requires major upgrade.

So, towards 1.9.2 release, we plan to pass on the fix of this issue,
by prohibiting super in such a situation (the above code raises an
NotImplementedError). We will fix it in 1.9.3 or later.

You can use Module#include as a workaround (`subseq' belong to the
Workaround module, so the above issue does not occur):

module Workaround
def subseq
super.instance_eval(& Overlaid)
end
end

Overlaid =proc do
p self
class<<self
include Workaround
end
end

You can also use eval (the lexical definition is duplicated):

Overlaid = proc do
p self
class<<self
eval %q{
def subseq
super.instance_eval(& Overlaid)
end
}
end
end

--
Yusuke Endoh
=end

Actions #4

Updated by wanabe (_ wanabe) over 14 years ago

  • Status changed from Assigned to Closed

=begin
This issue was solved with changeset r29063.
Yusuke, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0