[#44925] [Backport93 - Backport #5702][Open] backport r33935 — Yusuke Endoh <mame@...>

19 messages 2011/12/03

[#44940] Re: [ruby-cvs:41134] naruse:r33956 (trunk): Comment out tests which fails with GDBM-DBM compat mode. — Tanaka Akira <akr@...>

2011/12/6 <[email protected]>:

9 messages 2011/12/05
[#44941] Re: [ruby-cvs:41134] naruse:r33956 (trunk): Comment out tests which fails with GDBM-DBM compat mode. — KOSAKI Motohiro <kosaki.motohiro@...> 2011/12/05

2011年12月5日16:56 Tanaka Akira <[email protected]>:

[#44942] Re: [ruby-cvs:41134] naruse:r33956 (trunk): Comment out tests which fails with GDBM-DBM compat mode. — KOSAKI Motohiro <kosaki.motohiro@...> 2011/12/05

> おかしいな。gdbmは勝手にcreateフラグを立ててしまうので当該2つの

[#44985] [ruby-trunk - Bug #5757][Open] main threadがreadやselectで待っていると、^C でなかなか死なない — Yui NARUSE <naruse@...>

12 messages 2011/12/13

[#45021] [ruby-trunk - Bug #5786][Open] LoadError: cannot load such file -- openssl — Kazuhiro NISHIYAMA <redmine@...>

11 messages 2011/12/21

[#45057] [ruby-trunk - Feature #5820][Assigned] Merge Onigmo to Ruby 2.0 — Yui NARUSE <naruse@...>

21 messages 2011/12/28

[ruby-dev:45041] [ruby-trunk - Bug #5801] Enumerable#take_while の proc を外に出して使うと Segv

From: satoshi shiba <shiba@...>
Date: 2011-12-23 08:45:21 UTC
List: ruby-dev #45041
Issue #5801 has been updated by satoshi shiba.


Enumerable#grep なども同様の問題がありますね。
以下の再現コードで Segv を吐きます。

enum.c で、XX_i という形の関数の第二引数が C の
スタックへのポインタになってるやつは、全部同じ問題を
含んでいるのではないでしょうか。

# 再現コード
=begin
class A
  include Enumerable
  def each(&b)
    $block = b
    yield
  end
end
puts A.new.grep(//)
100.times{$block.call}
=end


static VALUE
grep_i(VALUE i, VALUE args, int argc, VALUE *argv)
{
    VALUE *arg = (VALUE *)args; /* arg は C のスタックを指す */
    ENUM_WANT_SVALUE();

    if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
        rb_ary_push(arg[1], i);
    }
    return Qnil;
}

----------------------------------------
Bug #5801: Enumerable#take_while の proc を外に出して使うと Segv
https://bugs.ruby-lang.org/issues/5801

Author: satoshi shiba
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: 1.9.3
ruby -v: ruby 1.9.3p6 (2011-12-20 revision 34080) [i686-linux]


芝と申します。

下の再現コードのように、Enumerable#take_while の Proc を
外に出して使うと Segv が発生します。

# 再現コード
=begin
class A
  include Enumerable
  def each(&b)
    $block = b
    yield
  end
end
puts A.new.take_while{true}
100.times{$block.call}
=end


$block には、take_while 内で使用する take_while_i (enum.c)
が C の Proc として入ります。この Proc を上の例のように
グローバル変数などに入れて、take_while の呼出し後に使用
すると Segv を吐きます。

原因はおそらく、enum_take_while と take_while_i で、
take_while の返り値である配列オブジェクトをポインタ経由で
渡していることではないでしょうか。

/* enum_take_while と take_while_i */
static VALUE
enum_take_while(VALUE obj)
{
  VALUE ary;
  RETURN_ENUMERATOR(obj, 0, 0);
  ary = rb_ary_new();
  rb_block_call(obj, id_each, 0, 0, take_while_i, (VALUE)&ary /* <= ココ */);
  return ary;
}

static VALUE
take_while_i(VALUE i, VALUE *ary /* <= ココ */, int argc, VALUE *argv)
{
  if (!RTEST(enum_yield(argc, argv))) rb_iter_break();
  rb_ary_push(*ary /* <= ココ */, enum_values_pack(argc, argv));
  return Qnil;
}


enum_take_while では rb_block_call を呼び出すときに &ary を
引数として渡していますが、ary は C のローカル変数であるため、
C のスタックを指すことになります。このため、take_while の
呼出し後にグローバル変数などに保持された Proc から take_while_i
が呼び出されると、*ary の値が書き換わってしまっていて Segv を
吐いているように見えます。

以下のパッチでこのバグが再現しないことは確認できました。
参考にしていただければ幸いです。
よろしくお願いいたします。

/* パッチ */
Index: enum.c
===================================================================
--- enum.c      (revision 34107)
+++ enum.c      (working copy)
@@ -2053,7 +2053,7 @@
 take_while_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
 {
     if (!RTEST(enum_yield(argc, argv))) rb_iter_break();
-    rb_ary_push(*ary, enum_values_pack(argc, argv));
+    rb_ary_push((VALUE)ary, enum_values_pack(argc, argv));
     return Qnil;
 }

@@ -2079,7 +2079,7 @@

     RETURN_ENUMERATOR(obj, 0, 0);
     ary = rb_ary_new();
-    rb_block_call(obj, id_each, 0, 0, take_while_i, (VALUE)&ary);
+    rb_block_call(obj, id_each, 0, 0, take_while_i, ary);
     return ary;
 }



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

In This Thread