Bug #1105
closedRuby1.9でのrescue節の例外ハンドラのマッチの処理
Description
=begin
河井です。
Ruby1.9とRuby1.8では、例外ハンドルクラスのリストにExceptionのサブ
クラス以外のオブジェクトが含まれている場合の挙動に違いがあります。
例えば以下のプログラムを実行した場合、
begin
raise
rescue Object.new, RuntimeError => e
p e
end
ruby 1.9.2dev (2009-02-02 trunk 21974)
[i686-linux]の場合の実行結果以下で
=> RuntimeError¶
Object.new が無視され、例外が補足されるようです。
ruby 1.8.7 (2008-08-11 patchlevel 72)
[i486-linux]の場合の実行結果は
=> /tmp/test.rb:3: class or module required for rescue clause (TypeError)¶
となり、Object.neweがExceptionのサブクラスでないので例外が発生します。
参考までに、以下のコードの実行結果は1.9と1.8とも同で
RuntimeErrorが補足される結果となります。
begin
raise
rescue RuntimeError, Object.new => e
p e
end
--
河井達治
=end
Updated by nobu (Nobuyoshi Nakada) over 16 years ago
=begin
なかだです。
At Wed, 4 Feb 2009 16:45:09 +0900,
Tatsuji Kawai wrote in [ruby-dev:37898]:
Ruby1.9とRuby1.8では、例外ハンドルクラスのリストにExceptionのサブ
クラス以外のオブジェクトが含まれている場合の挙動に違いがあります。
これでどうでしょうか。
Index: compile.c¶
--- compile.c (revision 22030)
+++ compile.c (working copy)
@@ -3488,7 +3488,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_
case NODE_ARRAY:
while (narg) {
-
ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); COMPILE(ret, "rescue arg", narg->nd_head); ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
-
ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
-
ADD_SEND(ret, nd_line(node), ID2SYM(id_core_handle_rescue_single), INT2FIX(2)); ADD_INSNL(ret, nd_line(node), branchif, label_hit); narg = narg->nd_next;
@@ -3498,9 +3499,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_
case NODE_ARGSCAT:
case NODE_ARGSPUSH:
-
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
-
ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); COMPILE(ret, "rescue/cond splat", narg);
-
ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue);
-
ADD_INSN(ret, nd_line(node), swap);
-
ADD_INSN(ret, nd_line(node), pop);
-
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
-
ADD_SEND(ret, nd_line(node), ID2SYM(id_core_handle_rescue_array), INT2FIX(2)); ADD_INSNL(ret, nd_line(node), branchif, label_hit); break;
Index: id.c¶
--- id.c (revision 22030)
+++ id.c (working copy)
@@ -22,15 +22,17 @@ Init_id(void)
REGISTER_SYMID(idNULL, "");
- REGISTER_SYMID(idIFUNC, ""),
- REGISTER_SYMID(idCFUNC, ""),
- REGISTER_SYMID(idRespond_to, "respond_to?"),
- REGISTER_SYMID(idThrowState, "#ThrowState"),
- REGISTER_SYMID(idIFUNC, "");
- REGISTER_SYMID(idCFUNC, "");
- REGISTER_SYMID(idRespond_to, "respond_to?");
- REGISTER_SYMID(idThrowState, "#ThrowState");
- REGISTER_SYMID(id_core_set_method_alias, "core#set_method_alias"),
- REGISTER_SYMID(id_core_set_variable_alias, "core#set_variable_alias"),
- REGISTER_SYMID(id_core_undef_method, "core#undef_method"),
- REGISTER_SYMID(id_core_define_method, "core#define_method"),
- REGISTER_SYMID(id_core_define_singleton_method, "core#define_singleton_method"),
- REGISTER_SYMID(id_core_set_postexe, "core#set_postexe"),
-
REGISTER_SYMID(id_core_set_method_alias, "core#set_method_alias");
-
REGISTER_SYMID(id_core_set_variable_alias, "core#set_variable_alias");
-
REGISTER_SYMID(id_core_undef_method, "core#undef_method");
-
REGISTER_SYMID(id_core_define_method, "core#define_method");
-
REGISTER_SYMID(id_core_define_singleton_method, "core#define_singleton_method");
-
REGISTER_SYMID(id_core_set_postexe, "core#set_postexe");
-
REGISTER_SYMID(id_core_handle_rescue_single, "core#handle_rescue_single");
-
REGISTER_SYMID(id_core_handle_rescue_array, "core#handle_rescue_array");
REGISTER_SYMID(idEach, "each");
Index: id.h
===================================================================
--- id.h (revision 22030)
+++ id.h (working copy)
@@ -69,5 +69,7 @@ enum ruby_method_ids {
id_core_define_singleton_method = 374,
id_core_set_postexe = 375,
- tLAST_TOKEN = 376,
- id_core_handle_rescue_single = 376,
- id_core_handle_rescue_array = 377,
- tLAST_TOKEN = 378,
#endif
idPLUS = '+',
@@ -157,5 +159,7 @@ ruby_method_id_check_for(id_core_define_
ruby_method_id_check_for(id_core_define_singleton_method, 374);
ruby_method_id_check_for(id_core_set_postexe, 375);
-ruby_method_id_check_for(tLAST_TOKEN, 376);
+ruby_method_id_check_for(id_core_handle_rescue_single, 376);
+ruby_method_id_check_for(id_core_handle_rescue_array, 377);
+ruby_method_id_check_for(tLAST_TOKEN, 378);
};
#endif
Index: parse.y
===================================================================
--- parse.y (revision 22030)
+++ parse.y (working copy)
@@ -758,4 +758,6 @@ static void token_info_pop(struct parser
%nonassoc id_core_define_singleton_method
%nonassoc id_core_set_postexe
+%nonassoc id_core_handle_rescue_single
+%nonassoc id_core_handle_rescue_array
%token tLAST_TOKEN
Index: vm.c¶
--- vm.c (revision 22030)
+++ vm.c (working copy)
@@ -1825,4 +1825,36 @@ nsdr(void)
}
+static VALUE
+check_rescue_arg(VALUE klass)
+{
- if (!rb_obj_is_kind_of(klass, rb_cModule)) {
- VALUE args[3];
- args[0] = rb_eTypeError;
- args[1] = rb_str_new2("class or module required for rescue clause");
- args[2] = vm_backtrace(GET_THREAD(), 0);
- rb_exc_raise(rb_make_exception(sizeof(args) / sizeof(args[0]), args));
- }
- return klass;
+}
+static VALUE
+m_core_handle_rescue_single(VALUE self, VALUE klass, VALUE exc)
+{
- check_rescue_arg(klass);
- return rb_funcall(klass, idEqq, 1, exc);
+}
+static VALUE
+m_core_handle_rescue_array(VALUE self, VALUE klass, VALUE ary)
+{
- long i;
- check_rescue_arg(klass);
- for (i = 0; i < RARRAY_LEN(ary); ++i) {
- VALUE result = rb_funcall(klass, idEqq, 1, RARRAY_PTR(ary)[i]);
- if (RTEST(result)) return result;
- }
- return Qfalse;
+}
void
Init_VM(void)
@@ -1846,4 +1878,6 @@ Init_VM(void)
rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3);
rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1);
- rb_define_method_id(klass, id_core_handle_rescue_single, m_core_handle_rescue_single, 2);
- rb_define_method_id(klass, id_core_handle_rescue_array, m_core_handle_rescue_array, 2);
rb_obj_freeze(fcore);
rb_gc_register_mark_object(fcore);
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦
=end
Updated by matz (Yukihiro Matsumoto) over 16 years ago
=begin
まつもと ゆきひろです
In message "Re: [ruby-dev:37903] Re: [Bug #1105] Ruby1.9でのrescue節の例外ハンドラのマッチの処理"
on Wed, 4 Feb 2009 20:21:21 +0900, Nobuyoshi Nakada [email protected] writes:
|At Wed, 4 Feb 2009 16:45:09 +0900,
|Tatsuji Kawai wrote in [ruby-dev:37898]:
|> Ruby1.9とRuby1.8では、例外ハンドルクラスのリストにExceptionのサブ
|> クラス以外のオブジェクトが含まれている場合の挙動に違いがあります。
|
|これでどうでしょうか。
ささだくんがよければコミットしてください。
=end
Updated by ko1 (Koichi Sasada) over 16 years ago
=begin
ささだです.
Nobuyoshi Nakada wrote::
+static VALUE
+m_core_handle_rescue_single(VALUE self, VALUE klass, VALUE exc)
+{
- check_rescue_arg(klass);
-
check_rescue_arg(exc);
- return rb_funcall(klass, idEqq, 1, exc);
+}+static VALUE
+m_core_handle_rescue_array(VALUE self, VALUE klass, VALUE ary)
+{
- long i;
- check_rescue_arg(klass);
- for (i = 0; i < RARRAY_LEN(ary); ++i) {
-
VALUE exc = RARRAY_PTR(ary)[i];
-
check_rescue_arg(exc);
- VALUE result = rb_funcall(klass, idEqq, 1, exc);
- if (RTEST(result)) return result;
- }
- return Qfalse;
+}
じゃなくていいんでしたっけ.つまり,投げられたほうじゃなくて,受ける方
をチェック.メソッド呼び出しが一回増えるのが,性能的にどの程度 impact が
あるのかよくわからないのですが.
そもそも,これは以前まつもとさんに「この仕様でいいですかね」と確認を¶
とったんだけどなぁ.¶
=> [yarv-dev:175] Re: eval in rescue clause¶
--
// SASADA Koichi at atdot dot net
=end
Updated by matz (Yukihiro Matsumoto) over 16 years ago
=begin
まつもと ゆきひろです
In message "Re: [ruby-dev:37922] Re: [Bug #1105] Ruby1.9でのrescue節の例外ハンドラのマッチの処理"
on Thu, 5 Feb 2009 23:58:56 +0900, SASADA Koichi [email protected] writes:
|# そもそも,これは以前まつもとさんに「この仕様でいいですかね」と確認を
|# とったんだけどなぁ.
|# => [yarv-dev:175] Re: eval in rescue clause
おお、すっかり忘れてました。
それならそれで、rejectしても構いません。
仕様としては「raiseにはExceptionのサブクラスが必要、rescueで
は===によるチェックを行う(ただしExceptionかどうかののチェック
を含んでも構わない)」くらいでしょうかね。> 関係者
=end