中川といいます。

[ruby-dev:31761] で一度レポートしたのですが、Array の基 
本的なところのバグで重要だと思われるので、もう一度詳しくレ 
ポートします。

Array#slice! で、負の範囲外の index を指定した場合、例 
外にならないことがあります。
trunk と 1.8 で再現します。

具体的には、

   $ ./ruby -e 'a = %w|a b c d e|; a.slice!(-3,2); p a'
   ["a", "b", "e"]

   $ ./ruby -e 'a = %w|a b c d e|; a.slice!(-8,2); p a'
   ["a", "b", "e"]

のような場合です。
この場合、-3 と -8 が同一視されてしまっています。

   $ ./ruby -e 'a = %w|a b c d e|; a.slice!(-13,2); p a'
   -e:1:in `slice!': index -8 out of array (IndexError)
           from -e:1:in `<main>'

ためしに -13 を指定すると、index -8 は範囲外だと 
いうエラーになるので、どこかで Array#size を誤って足し 
てしまっていることがわかります。

ソースを見ると、rb_ary_slice_bang 自体と、そこから呼んでい 
る rb_ary_splice で2度足し込んでしまっているようです。

以下のパッチで、

   $ ./ruby -e 'a = %w|a b c d e|; a.slice!(-3,2); p a'
   ["a", "b", "e"]

   $ ./ruby -e 'a = %w|a b c d e|; a.slice!(-8,2); p a'
   -e:1:in `slice!': index -8 out of array (IndexError)
           from -e:1:in `<main>'

と正しく動作することを確認しました。


Index: array.c
===================================================================
--- array.c	(revision 14178)
+++ array.c	(working copy)
@@ -1886,9 +1886,6 @@
  	pos = NUM2LONG(arg1);
  	len = NUM2LONG(arg2);
        delete_pos_len:
-	if (pos < 0) {
-	    pos = RARRAY_LEN(ary) + pos;
-	}
  	arg2 = rb_ary_subseq(ary, pos, len);
  	rb_ary_splice(ary, pos, len, Qundef);	/* Qnil/rb_ary_new2(0) */
  	return arg2;

--
Satoshi Nakagawa