Bug #2402

super in instance_eval

Added by Shugo Maeda over 4 years ago. Updated over 1 year ago.

[ruby-dev:39772]
Status:Closed
Priority:High
Assignee:Yukihiro Matsumoto
Category:core
Target version:2.0.0
ruby -v:ruby 1.9.2dev (2009-11-24 trunk 25909) [i686-linux] Backport:

Description

=begin
instanceevalのブロック内でsuperを呼ぶと、instanceevalで変更された
selfに対してsuperの呼び出しを行ってしまうようです。

defiant:build$ cat t.rb
class Foo
def foo
p self
end
end

class Bar < Foo
def foo
x = Object.new
x.instance_eval do
super
end
end
end

Bar.new.foo
defiant:build$ ./ruby-trunk.1124 -v t.rb
ruby 1.9.2dev (2009-11-24 trunk 25909) [i686-linux]
#Object:0x8590f6c

Foo#fooが呼ばれるのにselfがObjectという、ちょっとおかしなことになっています。
ちょっと自信がありませんが、一応パッチを添付します。
=end

super_in_instance_eval_fix.diff Magnifier (2.03 KB) Shugo Maeda, 11/25/2009 05:55 PM


Related issues

Related to ruby-trunk - Bug #3136: reuse of singleton method definition causes SEGV Closed 04/12/2010

Associated revisions

Revision 36640
Added by Shugo Maeda over 1 year ago

  • internal.h, class.c, eval.c, insns.def: find the appropriate receiver for super called in instance_eval. If such a receiver is not found, raise NoMethodError. [Bug #2402]

Revision 38761
Added by Shugo Maeda over 1 year ago

  • vminsnhelper.c (vmsearchsupermethod): raise a TypeError instead of a NotImplementError if self is not an instance of the current class. [Bug #2402]

History

#1 Updated by Shugo Maeda over 4 years ago

=begin
特異クラス定義でsuperした時はNoMethodErrorになるようです。

defiant:build$ cat t2.rb

class Foo
def foo
p self
end
end

class Bar < Foo
def foo
x = Object.new
class << x
super
end
end
end

Bar.new.foo
defiant:build$ ./ruby-trunk.1124 -v t2.rb
ruby 1.9.2dev (2009-11-24 trunk 25909) [i686-linux]
t2.rb:11:in singletonclass': super called outside of method (NoMethodError)
from t2.rb:10:in
foo'
from t2.rb:16:in `'

1.8ではFoo#fooが呼ばれます。

defiant:build$ ruby-1_8 -v t2.rb

ruby 1.8.8dev (2009-10-22 revision 25430) [i686-linux]
#Bar:0xb7ea443c

参考までに他の処理系では以下のような挙動でした。

defiant:build$ ir -v t2.rb
IronRuby 0.9.1.0 on .NET 2.0.0.0
#Bar:0x0000056
defiant:build$ jruby -v t2.rb
jruby 1.5.0.dev (ruby 1.8.7 patchlevel 174) (2009-11-12 421150b) (Java HotSpot(TM) Client VM 1.6.0_16) [i386-java]
#Class:#<Object:0x180cf2a>
defiant:build$ rbx -v t2.rb
rubinius 0.13.0-dev (1.8.7 e614007b 2009-11-06) [i686-pc-linux-gnu]
An exception occurred running t2.rb
No method 'bytecode' on an instance of NilClass. (NoMethodError)

それぞれ個性があって面白いですね。

個人的には例外でもいいんじゃないかなと思いますが、1.9のinstance_evalでの
superや、JRubyの特異クラス定義でのsuperのように、変なレシーバでsuperが
呼ばれてしまうのはまずいんじゃないかと思います。
=end

#2 Updated by ujihisa . over 4 years ago

  • Status changed from Open to Assigned
  • Assignee set to Yukihiro Matsumoto

=begin

=end

#3 Updated by Yusuke Endoh about 4 years ago

  • Assignee changed from Yukihiro Matsumoto to Koichi Sasada

=begin
遠藤です。

instanceevalのブロック内でsuperを呼ぶと、instanceevalで変更された
selfに対してsuperの呼び出しを行ってしまうようです。

再現しました。以下で SEGV することも確認しました。

class MyArray < Array
def reverse
"foo".instance_eval do
super
end
end
end
MyArray.new([1,2,3]).reverse

パッチも見ました。速度劣化は気になりますが、正しいと思います。

vmsearchsuperclass を追ってみたところ、recv が必要になるのは、
現在のコンテキストが include された module に所属するメソッドの
場合 (ICLASS) だけのようですので、その時まで recv の同定を遅延
させると、速度劣化も気にならなくなるかもと思います。

ただ、その辺の修正は の修正の後にやったほうが
いい予感がするので、最適化は後にして、とりあえずこの問題は前田
さんのパッチで close するのがいいと思います。

--
Yusuke Endoh mame@tsg.ne.jp
=end

#4 Updated by Koichi Sasada almost 4 years ago

=begin
パッチは全然見てないのですが,遠藤さんが良いと仰ってるので良いのではないかと思います.
=end

#5 Updated by Yusuke Endoh almost 4 years ago

  • Target version set to 2.0.0

=begin
遠藤です。

[Bug #2502] [Bug #3136] あたりで super の修正は後回しにしようということに
なり、r28043 でとりあえずの対策をしたので、1.9.x にします。

--
Yusuke Endoh mame@tsg.ne.jp
=end

#6 Updated by Hiroshi Nakamura almost 3 years ago

  • Target version changed from 2.0.0 to 1.9.3

#7 Updated by Koichi Sasada almost 3 years ago

  • Target version changed from 1.9.3 to 2.0.0

すみません,1.9.4 送りで....

#8 Updated by Shugo Maeda over 1 year ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r36640.
Shugo, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • internal.h, class.c, eval.c, insns.def: find the appropriate receiver for super called in instance_eval. If such a receiver is not found, raise NoMethodError. [Bug #2402]

#9 Updated by Shugo Maeda over 1 year ago

  • Status changed from Closed to Open

Reopened the issue because r36640 is reverted by r36795.

#10 Updated by Koichi Sasada over 1 year ago

  • Priority changed from Normal to High

shugo-san
これ,どういう話でしたっけ.

#11 Updated by Shugo Maeda over 1 year ago

ko1 (Koichi Sasada) wrote:

shugo-san
これ,どういう話でしたっけ.

instance_evalの中でsuperを呼んだ時に正しいレシーバを見つけるために r36640 で外側のフレームを辿る
ようにしたのですが、 Bug #6907 の問題があったので r36795 でrevertしました。

現状はNotImplementedErrorがraiseされますが、こういうケースでsuperが呼べないのを仕様ということに
するなら(selfのtypeがおかしいという意味で)TypeErrorが妥当ですかねえ。

#12 Updated by Shugo Maeda over 1 year ago

shugo (Shugo Maeda) wrote:

instance_evalの中でsuperを呼んだ時に正しいレシーバを見つけるために r36640 で外側のフレームを辿る
ようにしたのですが、 Bug #6907 の問題があったので r36795 でrevertしました。

現状はNotImplementedErrorがraiseされますが、こういうケースでsuperが呼べないのを仕様ということに
するなら(selfのtypeがおかしいという意味で)TypeErrorが妥当ですかねえ。

一点補足すると、1.8ではinstanceevalではフレームのselfは変えずにrbevalの引数だけ変えているみたいなので
instance_evalの中でsuperした時もちゃんと元のselfが使われるようですが、このためだけにselfを二重に持つのは
何だかなあという気がしています。
でもorphanなProcからsuperを呼んだ時とかを考えると他の方法を思い付きません。

#13 Updated by Masaya Tarui over 1 year ago

  • Status changed from Open to Assigned

#14 Updated by Shugo Maeda over 1 year ago

  • Assignee changed from Koichi Sasada to Yukihiro Matsumoto

まつもとさん、この件どうしましょうか?

個人的にはinstance_evalの中でsuperを呼ぶのはかなり特殊なケースだと思うので、
TypeErrorでよいように思いますが。

#15 Updated by Shugo Maeda over 1 year ago

  • Category set to core

shugo (Shugo Maeda) wrote:

まつもとさん、この件どうしましょうか?

個人的にはinstance_evalの中でsuperを呼ぶのはかなり特殊なケースだと思うので、
TypeErrorでよいように思いますが。

まつもとさん、いかがでしょうか。

再度まとめると、以下のようにinstance_eval中でsuperを呼ぶと、superで
呼び出した先のクラス・モジュールとselfの整合性が取れなくなるため、
現状では、NotImplementedErrorが発生します。

class Bar < Foo
def foo
x = Object.new
x.instance_eval do
super
end
end
end

NotImplementedErrorなのは、将来1.8と同様に動くように実装するという意図だと
思いますが、次の点からこの場合はエラーでもよいのではないかと考えています。

  • 1.8とインタプリタの構造が異なるため、上記のコードを動くようにするには実装コストも 実行コストもかかる。 # 制御フレームを辿ってもとのselfを見つける修正を試みましたが、orphanなProcから # superを呼んだ時などに問題がありました。
  • 現状エラーが発生するが、誰も困っていなさそう。

ただ、この場合はエラーになるのが仕様ということにするのであれば、NotImplementedErrorは
不適切なので、TypeError(selfと呼び出し先メソッドのクラスが不整合という意味)などの他の
例外を発生させるようにしてはどうでしょうか。

#16 Updated by Yukihiro Matsumoto over 1 year ago

うーん、では、禁止でいいですよ。

Matz.

#17 Updated by Shugo Maeda over 1 year ago

  • Status changed from Assigned to Closed

This issue was solved with changeset r38761.
Shugo, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • vminsnhelper.c (vmsearchsupermethod): raise a TypeError instead of a NotImplementError if self is not an instance of the current class. [Bug #2402]

Also available in: Atom PDF