From: "nagachika (Tomoyuki Chikanaga)" Date: 2012-12-31T00:57:24+09:00 Subject: [ruby-dev:46821] [ruby-trunk - Bug #7638][Assigned] trunk で rails の activesupport のテストが失敗してしまう Issue #7638 has been updated by nagachika (Tomoyuki Chikanaga). Status changed from Open to Assigned Assignee set to nobu (Nobuyoshi Nakada) 柴田さん、いつもご報告ありがとうございます。 わたしの理解では r38175 は rb_obj_respond_to() と rb_funcall2() で「respond_to?(mid, true) でメソッドが呼べるかチェックしてから呼ぶ」という処理を rb_check_funcall() という1つの関数でまとめるようにしたというものだと思います。以下のようにすると確かに marshal_dump や _dump が呼ばれてその結果 method_missing に渡されています。(rails のテストケースとは違い、method_missing で super を呼んでNoMethodError を発生させています) class A def method_missing(m, *a) @call ||= [] @call << [m, a] end attr_reader :call end a = A.new Marshal.dump(a) p a.call # => [[:marshal_dump, []], [:_dump, [-2]]] rb_obj_respond_to() でのチェックはほぼ Ruby で書くと obj.respond_to?(m) && obj.send(m) と同様のことをしますが、check_funcall_respond_to() は respond_to? が再定義されていない場合には常に真を返していて、その後 check_funcall_callable() で実際にメソッドの定義の有無や可視性のチェックをして、呼べなかったら method_missing を呼ぶ(NoMethodError の rescue つきで)という挙動をするため、method_missing が呼ばれます。 marshal_dump が respond_to?(:marshal_dump, true) が false を返すのに呼ばれているのは確かに意外に感じます。ただこういう挙動は暗黙の型変換で to_int などが呼ばれる時にも同様に method_missing が呼ばれており、Marshal もどのような暗黙のメソッド呼び出しの挙動に揃えられただけという考えかたもできると思います。 (上の A の定義は略します) a = A.new Integer(a) rescue nil; p a.call # => [[:to_int, []], [:to_i, []]] なので一貫性を取るか互換性を取るかということではないかと思います。 確かに挙動は変化していますが、個人的な意見としては method_missing を呼ばなかったら呼ばなかったで暗黙に呼ばれるメソッドが method_missing を呼ばないぞって文句が出てくるような気もします。 ただ respond_to? が再定義されていると今度は method_missing が呼ばれなくなってしまいます。 上の例だと class A def respond_to?(m, priv=false) super end end が追加されると method_missing が呼ばれなくなります。 respond_to? の再定義というのも筋が悪いと思いますけど respond_to_missing? がまだ普及していなくて時々 gems パッケージのソースで見掛けた記憶があります。 あと method_missing に渡されたメソッドが常に result に対して呼べるつもりで書かれている activesupport のテストはいずれにしても直すべきじゃないかと思います。 ---------------------------------------- Bug #7638: trunk で rails の activesupport のテストが失敗してしまう https://bugs.ruby-lang.org/issues/7638#change-35159 Author: hsbt (Hiroshi SHIBATA) Status: Assigned Priority: Normal Assignee: nobu (Nobuyoshi Nakada) Category: core Target version: 2.0.0 ruby -v: ruby 2.0.0dev (2012-12-29 trunk 38656) [x86_64-darwin12.2.1] Ruby のバグとは言い切れませんが、ある時期から activesupport のテストが落ちるようになってしまいました。 Ruby と Rails のどちらを直すべきか判断できないので、何か教えて頂けると助かります。 落ちてしまうテストは https://github.com/rails/rails/blob/master/activesupport/test/core_ext/marshal_test.rb です。テストの実行方法は以下の通りです。 % git clone git://github.com/rails/rails.git % cd rails % gem install bundler --pre % bundle % cd activesupport % bundle exec ruby -Itest:lib test/core_ext/marshal_test.rb テストを実行すると Thread の deadlock が発生しますが、Thread.abort_on_exception = true で実行すると https://github.com/rails/rails/blob/master/activesupport/lib/active_support/testing/isolation.rb#L31 の method_missing 部分で marshal_load が @calls に追加され、この @calls が L26 で send されて NoMethodError で落ちていることがわかりました。 いつから落ち始めたかを調べたところ、 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38175 の変更によって、_dump が @calls に追加されるようになり、rails のテストが落ちはじめ http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38568 の変更で _dump ではなく marshal_load が @calls に追加されるようになって今も落ち続けているという状態です。 Rails のコードに marshal_load と marshal_dump を定義すればテストは落ちなくなるのですが、38175 より前では 発生していなかった現象が発生するようになった原因など教えて頂けないでしょうか。 -- http://bugs.ruby-lang.org/