Project

General

Profile

Actions

Bug #2402

closed

super in instance_eval

Added by shugo (Shugo Maeda) over 14 years ago. Updated over 8 years ago.

Status:
Closed
Target version:
-
ruby -v:
ruby 1.9.2dev (2009-11-24 trunk 25909) [i686-linux]
Backport:
[ruby-dev:39772]

Description

instance_evalのブロック内でsuperを呼ぶと、instance_evalで変更された
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が呼ばれるのにselfObjectという、ちょっとおかしなことになっています。
ちょっと自信がありませんが、一応パッチを添付します。


Files

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

Related issues 2 (0 open2 closed)

Related to Ruby master - Bug #3136: reuse of singleton method definition causes SEGVClosedko1 (Koichi Sasada)04/12/2010Actions
Related to Ruby master - Bug #11636: super in instance_eval in a method defined in a module is invoked with a wrong receiverClosedko1 (Koichi Sasada)Actions
Actions #1

Updated by shugo (Shugo Maeda) over 14 years ago

特異クラス定義で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 `<main>'

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
呼ばれてしまうのはまずいんじゃないかと思います。

Actions #2

Updated by ujihisa (Tatsuhiro Ujihisa) over 14 years ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)
Actions #3

Updated by mame (Yusuke Endoh) almost 14 years ago

  • Assignee changed from matz (Yukihiro Matsumoto) to ko1 (Koichi Sasada)

遠藤です。

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

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

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

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

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

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

--
Yusuke Endoh

Actions #4

Updated by ko1 (Koichi Sasada) almost 14 years ago

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

Actions #5

Updated by mame (Yusuke Endoh) almost 14 years ago

  • Target version set to 2.0.0

遠藤です。

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

--
Yusuke Endoh

Updated by nahi (Hiroshi Nakamura) almost 13 years ago

  • Target version changed from 2.0.0 to 1.9.3

Updated by ko1 (Koichi Sasada) over 12 years ago

  • Target version changed from 1.9.3 to 2.0.0

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

Actions #8

Updated by shugo (Shugo Maeda) over 11 years 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. [ruby-dev:39772] [Bug #2402]

Updated by shugo (Shugo Maeda) over 11 years ago

  • Status changed from Closed to Open

Reopened the issue because r36640 is reverted by r36795.

Updated by ko1 (Koichi Sasada) over 11 years ago

  • Priority changed from Normal to 5

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

Updated by shugo (Shugo Maeda) over 11 years ago

ko1 (Koichi Sasada) wrote:

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

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

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

Updated by shugo (Shugo Maeda) over 11 years ago

shugo (Shugo Maeda) wrote:

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

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

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

Actions #13

Updated by tarui (Masaya Tarui) over 11 years ago

  • Status changed from Open to Assigned

Updated by shugo (Shugo Maeda) about 11 years ago

  • Assignee changed from ko1 (Koichi Sasada) to matz (Yukihiro Matsumoto)

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

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

Updated by shugo (Shugo Maeda) about 11 years 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と呼び出し先メソッドのクラスが不整合という意味)などの他の
例外を発生させるようにしてはどうでしょうか。

Updated by matz (Yukihiro Matsumoto) about 11 years ago

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

Matz.

Actions #17

Updated by shugo (Shugo Maeda) about 11 years 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.


  • vm_insnhelper.c (vm_search_super_method): raise a TypeError
    instead of a NotImplementError if self is not an instance of the
    current class. [ruby-dev:39772] [Bug #2402]

Updated by nobu (Nobuyoshi Nakada) over 8 years ago

  • Description updated (diff)
Actions #19

Updated by shugo (Shugo Maeda) over 8 years ago

  • Related to Bug #11636: super in instance_eval in a method defined in a module is invoked with a wrong receiver added
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0