[#18440] racc segv revisited — "Akinori MUSHA" <knu@...>

 次のバグの件なんですが、現時点では原因究明を含めて未解決という

24 messages 2002/10/02
[#18617] Re: racc segv revisited — "Akinori MUSHA" <knu@...> 2002/11/02

At Wed, 2 Oct 2002 23:19:59 +0900,

[ruby-dev:18531] Re: map in printf format

From: nobu.nakada@...
Date: 2002-10-16 10:24:12 UTC
List: ruby-dev #18531
なかだです。

# 忘れるところだった

At Wed, 13 Mar 2002 09:11:24 +0900,
Nobuyoshi-Nakada wrote:
> > 後者は(もしその挙動が正しければ)取り込みたいです。どういう挙
> > 動が正しいのか確認する手段はありますかね。glibcに合わせれば
> > それでよいのかな。
> 
> とりあえずglibc 2.2.4では以下のコードで2123と出力されますが、
> The Open Group Base Specifications Issue 6では混ぜるな、としっ
> かり書いてありました。使った場合の動作は決まってないようですが、
> 最後の例のように"%n$"は次の変換指定に影響するけど"*m$"はしない
> というのは、ちょっと不思議な気がします。

これはインプリメント例などより規格上未定義であることを優先して、
エラーにしたほうがいいという気がして来ました。

ついでに[ruby-core:00460]も。


Index: sprintf.c
===================================================================
RCS file: /cvs/ruby/src/ruby/sprintf.c,v
retrieving revision 1.25
diff -u -2 -p -r1.25 sprintf.c
--- sprintf.c	28 Aug 2002 08:05:23 -0000	1.25
+++ sprintf.c	13 Sep 2002 03:51:23 -0000
@@ -63,9 +63,11 @@ remove_sign_bits(str, base)
 #define FPREC  64
 
-#define CHECK(l) \
+#define CHECK(l) do {\
     while (blen + (l) >= bsiz) {\
-	REALLOC_N(buf, char, bsiz*2);\
 	bsiz*=2;\
-    }
+    }\
+    rb_str_resize(result, bsiz);\
+    buf = RSTRING(result)->ptr;\
+} while (0)
 
 #define PUSH(s, l) do { \
@@ -75,6 +77,16 @@ remove_sign_bits(str, base)
 } while (0)
 
-#define GETARG() \
-    ((nextarg >= argc) ? (rb_raise(rb_eArgError, "too few argument."), 0) : argv[nextarg++])
+#define GETARG() (nextvalue != Qundef ? nextvalue : \
+    posarg < 0 ? \
+    (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \
+    (posarg = nextarg++, GETNTHARG(posarg)))
+
+#define GETPOSARG(n) (posarg > 0 ? \
+    (rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg), 0) : \
+    ((n < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", n), 0) : \
+	       (posarg = -1, GETNTHARG(n))))
+
+#define GETNTHARG(nth) \
+    ((nth >= argc) ? (rb_raise(rb_eArgError, "too few argument."), 0) : argv[nth])
 
 #define GETASTER(val) do { \
@@ -88,8 +100,5 @@ remove_sign_bits(str, base)
     } \
     if (*p == '$') { \
-	int curarg = nextarg; \
-	nextarg = n; \
-	tmp = GETARG(); \
-	nextarg = curarg; \
+	tmp = GETPOSARG(n); \
     } \
     else { \
@@ -111,10 +120,12 @@ rb_f_sprintf(argc, argv)
 
     int width, prec, flags = FNONE;
-    int nextarg = 0;
+    int nextarg = 1;
+    int posarg = 0;
     int tainted = 0;
+    VALUE nextvalue;
     VALUE tmp;
     VALUE str;
 
-    fmt = GETARG();
+    fmt = GETNTHARG(0);
     if (OBJ_TAINTED(fmt)) tainted = 1;
     StringValue(fmt);
@@ -123,5 +134,6 @@ rb_f_sprintf(argc, argv)
     blen = 0;
     bsiz = 120;
-    buf = ALLOC_N(char, bsiz);
+    result = rb_str_buf_new(bsiz);
+    buf = RSTRING(result)->ptr;
 
     for (; p < end; p++) {
@@ -138,4 +150,5 @@ rb_f_sprintf(argc, argv)
 
 	width = prec = -1;
+	nextvalue = Qundef;
       retry:
 	switch (*p) {
@@ -182,5 +195,8 @@ rb_f_sprintf(argc, argv)
 	    }
 	    if (*p == '$') {
-		nextarg = n;
+		if (nextvalue != Qundef) {
+		    rb_raise(rb_eArgError, "value given twice - %d$", n);
+		}
+		nextvalue = GETPOSARG(n);
 		p++;
 		goto retry;
@@ -580,6 +596,5 @@ rb_f_sprintf(argc, argv)
     }
 #endif
-    result = rb_str_new(buf, blen);
-    free(buf);
+    rb_str_resize(result, blen);
 
     if (tainted) OBJ_TAINT(result);


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

In This Thread