Bug #3236: ISeq.load で [BUG] iseq_set_sequence: ic_index overflow が発生
http://redmine.ruby-lang.org/issues/show/3236

起票者: Tomoyuki Chikanaga
ステータス: Open, 優先度: Normal
担当者: Koichi Sasada, カテゴリ: YARV
ruby -v: ruby 1.9.2dev (2010-05-02 trunk 27590) [x86_64-darwin10.3.0]

RubyGems の iseq ライブラリを利用して、定数やインスタンス変数の参照を含むスクリプトをコンパイルしたものを load しようとすると以下のようなメッセージでエラーになります。

$ cat iseq_load.rb
require "iseq"

iseq = ISeq.compile("@a[0]")
puts iseq.disasm
ISeq.load(iseq.to_a)

$ ruby-trunk -v iseq_load.rb
ruby 1.9.2dev (2010-05-02 trunk 27590) [x86_64-darwin10.3.0]
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 getinstancevariable :@a, <ic:0>
0005 putobject        0
0007 opt_aref         <ic:2>
0009 leave            
iseq_load.rb:5: [BUG] iseq_set_sequence: ic_index overflow: index: 2, size: 0
ruby 1.9.2dev (2010-05-02 trunk 27590) [x86_64-darwin10.3.0]

-- control frame ----------
c:0004 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC  :load
c:0003 p:0075 s:0007 b:0007 l:0014a8 d:000bc0 EVAL   iseq_load.rb:5
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH
c:0001 p:0000 s:0002 b:0002 l:0014a8 d:0014a8 TOP   
---------------------------
-- Ruby level backtrace information ----------------------------------------
iseq_load.rb:5:in `<main>'
iseq_load.rb:5:in `load'

-- C level backtrace information -------------------------------------------
0   ruby-trunk                          0x0000000100177acb rb_vm_bugreport + 120
1   ruby-trunk                          0x0000000100034f90 report_bug + 313
2   ruby-trunk                          0x00000001000350b5 rb_bug + 241
3   ruby-trunk                          0x000000010014a328 iseq_set_sequence + 2456
4   ruby-trunk                          0x0000000100148f1c iseq_setup + 118
5   ruby-trunk                          0x00000001001590e5 iseq_build_body + 2250
6   ruby-trunk                          0x000000010015989f rb_iseq_build_from_ary + 1789
7   ruby-trunk                          0x000000010015bbe3 iseq_load + 1788
8   ruby-trunk                          0x000000010015bcb2 rb_iseq_load + 47
9   iseq.bundle                         0x0000000100540eb5 iseq_s_load + 53
10  ruby-trunk                          0x000000010016b040 call_cfunc + 282
11  ruby-trunk                          0x000000010016aea7 vm_call_cfunc + 284
12  ruby-trunk                          0x000000010016a07c vm_call_method + 373
13  ruby-trunk                          0x0000000100164cae vm_exec_core + 11207
14  ruby-trunk                          0x00000001001745e9 vm_exec + 147
15  ruby-trunk                          0x0000000100174fca rb_iseq_eval_main + 45
16  ruby-trunk                          0x0000000100039cd9 ruby_exec_internal + 193
17  ruby-trunk                          0x0000000100039dfd ruby_exec_node + 30
18  ruby-trunk                          0x0000000100039dd0 ruby_run_node + 56
19  ruby-trunk                          0x0000000100000dcb main + 79
20  ruby-trunk                          0x0000000100000d74 start + 52
21  ???                                 0x0000000000000003 0x0 + 3

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

配列から iseq を構築する時にインラインキャッシュのサイズ(ic_size)を復元していない為のようです。以下の修正で、make check でエラーが増えないことと、標準添付のライブラリ($prefix/lib/ruby/1.9.1/**/*.rb)が全て ISeq.load できることを確認しました。
ついでに、上記でひっかかっている ic_index と ic_size のチェックには等号が抜けているようでしたのでそれも追加しています。

Index: compile.c
===================================================================
--- compile.c	(revision 27590)
+++ compile.c	(working copy)
@@ -1434,7 +1434,7 @@
 			{
 			    int ic_index = FIX2INT(operands[j]);
 			    IC ic = &iseq->ic_entries[ic_index];
-			    if (UNLIKELY(ic_index > iseq->ic_size)) {
+			    if (UNLIKELY(ic_index >= iseq->ic_size)) {
 				rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d",
 				       ic_index, iseq->ic_size);
 			    }
@@ -5269,6 +5269,8 @@
 			break;
 		      case TS_IC:
 			argv[j] = op;
+			if (NUM2INT(op) >= iseq->ic_size)
+			    iseq->ic_size = NUM2INT(op) + 1;
 			break;
 		      case TS_ID:
 			argv[j] = rb_convert_type(op, T_SYMBOL,


----------------------------------------
http://redmine.ruby-lang.org