[ruby-dev:31864] Re: meta programming might dump core

From: Nobuyoshi Nakada <nobu@...>
Date: 2007-09-25 20:04:20 UTC
List: ruby-dev #31864
なかだです。

At Tue, 25 Sep 2007 02:49:24 +0900,
Yusuke ENDOH wrote in [ruby-dev:31850]:
> 約 100 万エントリのハッシュリテラル:

key=>valueの値を先にVMスタックにすべて積んでからnewhashを実行す
るので、そこでオーバーフローしています。一組ずつ追加していくとい
うのは、速度的な問題からささださんが気に入らないようで。

思い付くのはこのあたり。
(a) 速度は少々あきらめて、一組ずつ追加
(b) VMスタックを確保できるか確認する命令を追加

> 約 100 万変数の多重代入:

これもexpandarrayで100万個に展開するときにオーバーフローしていま
す。expandarrayはサイズがわかっているので、チェックを入れればい
いのではないかと。

> 約 100 万引数のメソッド呼び出し:

これも引数を一度スタックに全部積むので以下同文。

> false が || で 25000 個連なった式:
> 
> $ time ./ruby -ve 'eval("false||" * 25000 + "true")'
> ruby 1.9.0 (2007-09-24 patchlevel 0) [i686-linux]
> セグメンテーション違反です

こっちはbytecodeにコンパイルするところでマシンスタックオーバーフ
ローしています。

この例については回避するのは簡単ですが、もっと複雑にネストしてい
たりするとお手上げでしょう。


Index: compile.c
===================================================================
--- compile.c	(revision 13509)
+++ compile.c	(working copy)
@@ -1795,9 +1795,14 @@ compile_branch_condition(rb_iseq_t *iseq
 			 LABEL *then_label, LABEL *else_label)
 {
+  again:
     switch (nd_type(cond)) {
       case NODE_NOT:
-	compile_branch_condition(iseq, ret, cond->nd_body, else_label,
-				 then_label);
-	break;
+	{
+	    LABEL *tmp = else_label;
+	    else_label = then_label;
+	    then_label = tmp;
+	    cond = cond->nd_body;
+	    goto again;
+	}
 
       case NODE_AND:
@@ -1807,7 +1812,6 @@ compile_branch_condition(rb_iseq_t *iseq
 				     else_label);
 	    ADD_LABEL(ret, label);
-	    compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
-				     else_label);
-	    break;
+	    cond = cond->nd_2nd;
+	    goto again;
 	}
       case NODE_OR:
@@ -1817,7 +1821,6 @@ compile_branch_condition(rb_iseq_t *iseq
 				     label);
 	    ADD_LABEL(ret, label);
-	    compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
-				     else_label);
-	    break;
+	    cond = cond->nd_2nd;
+	    goto again;
 	}
       case NODE_LIT:		/* NODE_LIT is always not true */
@@ -3187,18 +3190,20 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_
       case NODE_OR:{
 	LABEL *end_label = NEW_LABEL(nd_line(node));
-	COMPILE(ret, "nd_1st", node->nd_1st);
-	if (!poped) {
-	    ADD_INSN(ret, nd_line(node), dup);
-	}
-	if (type == NODE_AND) {
-	    ADD_INSNL(ret, nd_line(node), branchunless, end_label);
-	}
-	else {
-	    ADD_INSNL(ret, nd_line(node), branchif, end_label);
-	}
-	if (!poped) {
-	    ADD_INSN(ret, nd_line(node), pop);
-	}
-	COMPILE_(ret, "nd_2nd", node->nd_2nd, poped);
+	do {
+	    COMPILE(ret, "nd_1st", node->nd_1st);
+	    if (!poped) {
+		ADD_INSN(ret, nd_line(node), dup);
+	    }
+	    if (type == NODE_AND) {
+		ADD_INSNL(ret, nd_line(node), branchunless, end_label);
+	    }
+	    else {
+		ADD_INSNL(ret, nd_line(node), branchif, end_label);
+	    }
+	    if (!poped) {
+		ADD_INSN(ret, nd_line(node), pop);
+	    }
+	} while ((node = node->nd_2nd) != 0 && nd_type(node) == type);
+	COMPILE_(ret, "nd_2nd", node, poped);
 	ADD_LABEL(ret, end_label);
 	break;


-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

In This Thread

Prev Next