[#30220] schedule for Ruby 1.8.6 — "Akinori MUSHA" <knu@...>

 ruby-core を読んでいない人もいると思うので、ここでもアナウンス

20 messages 2007/01/30

[ruby-dev:30101] Re: StringScanner#scan BUG?

From: Minero Aoki <aamine@...>
Date: 2007-01-07 01:34:15 UTC
List: ruby-dev #30101
青木です。すみません、すっかり見落としてました。

  In mail "[ruby-dev:29914] StringScanner#scan BUG?"
  とみたまさひろ <tommy@tmtm.org> wrote:

> とみたです。
> 
> Ruby 1.8.5 で次のコードを実行すると、$KCODE="NONE" かつ正規表現のフラ
> グが e, s, u の場合に、"a:b" を返します。
> 
> require "strscan"
> str = "a:b"
> ["NONE", "EUC", "SJIS", "UTF8"].each do |code|
>   p code
>   $KCODE = code
>   p StringScanner.new(str).scan(/[^\x01\:]+/n)
>   p StringScanner.new(str).scan(/[^\x01\:]+/e)
>   p StringScanner.new(str).scan(/[^\x01\:]+/s)
>   p StringScanner.new(str).scan(/[^\x01\:]+/u)
> end
> 
> [^\x01\:] を [^\:\x01] にすると発生しません。期待どおり "a" を返します。
> 
> はじめは Ruby 本体の正規表現のバグかと思ったのですが、StringScanner 以
> 外では発生しないようです。

strscan.c で kcode_set_option を呼んでなかったのが原因でした。

以下のパッチで修正できるのですが、1.8 ブランチにコミットしてよいでしょうか?
extern 関数が 2 つ増えます。

Index: intern.h
===================================================================
RCS file: /var/cvs/src/ruby/intern.h,v
retrieving revision 1.139.2.21
diff -u -r1.139.2.21 intern.h
--- intern.h	30 Oct 2006 02:24:08 -0000	1.139.2.21
+++ intern.h	7 Jan 2007 01:33:27 -0000
@@ -370,6 +370,8 @@
 int rb_reg_options _((VALUE));
 void rb_set_kcode _((const char*));
 const char* rb_get_kcode _((void));
+void rb_kcode_set_option _((VALUE));
+void rb_kcode_reset_option _((void));
 /* ruby.c */
 RUBY_EXTERN VALUE rb_argv;
 RUBY_EXTERN VALUE rb_argv0;
Index: re.c
===================================================================
RCS file: /var/cvs/src/ruby/re.c,v
retrieving revision 1.114.2.20
diff -u -r1.114.2.20 re.c
--- re.c	20 Jul 2006 07:04:17 -0000	1.114.2.20
+++ re.c	7 Jan 2007 01:31:23 -0000
@@ -200,8 +200,8 @@
 
 static int curr_kcode;
 
-static void
-kcode_set_option(re)
+void
+rb_kcode_set_option(re)
     VALUE re;
 {
     if (!FL_TEST(re, KCODE_FIXED)) return;
@@ -224,8 +224,8 @@
     }
 }	  
 
-static void
-kcode_reset_option()
+void
+rb_kcode_reset_option()
 {
     if (reg_kcode == curr_kcode) return;
     switch (reg_kcode) {
@@ -253,9 +253,9 @@
 
     if (!FL_TEST(re, KCODE_FIXED))
 	return mbclen(c);
-    kcode_set_option(re);
+    rb_kcode_set_option(re);
     len = mbclen(c);
-    kcode_reset_option();
+    rb_kcode_reset_option();
     return len;
 }
 
@@ -486,11 +486,11 @@
 	}
 	if (*ptr == ':' && ptr[len-1] == ')') {
 	    Regexp *rp;
-	    kcode_set_option(re);
+	    rb_kcode_set_option(re);
 	    rp = ALLOC(Regexp);
 	    MEMZERO((char *)rp, Regexp, 1);
 	    err = re_compile_pattern(++ptr, len -= 2, rp) != 0;
-	    kcode_reset_option();
+	    rb_kcode_reset_option();
 	    re_free_pattern(rp);
 	}
 	if (err) {
@@ -849,7 +849,7 @@
 	char *err;
 
 	if (FL_TEST(re, KCODE_FIXED))
-	    kcode_set_option(re);
+	    rb_kcode_set_option(re);
 	rb_reg_check(re);
 	RREGEXP(re)->ptr->fastmap_accurate = 0;
 	err = re_compile_pattern(RREGEXP(re)->str, RREGEXP(re)->len, RREGEXP(re)->ptr);
@@ -870,9 +870,9 @@
     if (may_need_recompile) rb_reg_prepare_re(re);
 
     if (FL_TEST(re, KCODE_FIXED))
-	kcode_set_option(re);
+	rb_kcode_set_option(re);
     else if (reg_kcode != curr_kcode)
-	kcode_reset_option();
+	rb_kcode_reset_option();
 
     if (reverse) {
 	range = -pos;
@@ -904,9 +904,9 @@
     if (may_need_recompile) rb_reg_prepare_re(re);
 
     if (FL_TEST(re, KCODE_FIXED))
-	kcode_set_option(re);
+	rb_kcode_set_option(re);
     else if (reg_kcode != curr_kcode)
-	kcode_reset_option();
+	rb_kcode_reset_option();
 
     if (reverse) {
 	range = -pos;
@@ -918,7 +918,7 @@
 		       pos, range, &regs);
 
     if (FL_TEST(re, KCODE_FIXED))
-	kcode_reset_option();
+	rb_kcode_reset_option();
 
     if (result == -2) {
 	rb_reg_raise(RREGEXP(re)->str, RREGEXP(re)->len,
@@ -1364,7 +1364,7 @@
     }
 
     if (options & ~0xf) {
-	kcode_set_option((VALUE)re);
+	rb_kcode_set_option((VALUE)re);
     }
     if (ruby_ignorecase) {
 	options |= RE_OPTION_IGNORECASE;
@@ -1376,7 +1376,7 @@
     re->str[len] = '\0';
     re->len = len;
     if (options & ~0xf) {
-	kcode_reset_option();
+	rb_kcode_reset_option();
     }
     if (ruby_in_compile) FL_SET(obj, REG_LITERAL);
 }
@@ -1839,7 +1839,7 @@
     }
     StringValue(str);
     str = rb_reg_quote(str);
-    kcode_reset_option();
+    rb_kcode_reset_option();
     return str;
 }
 
Index: ext/strscan/strscan.c
===================================================================
RCS file: /var/cvs/src/ruby/ext/strscan/strscan.c,v
retrieving revision 1.7.2.8
diff -u -r1.7.2.8 strscan.c
--- ext/strscan/strscan.c	26 Jul 2006 09:37:00 -0000	1.7.2.8
+++ ext/strscan/strscan.c	7 Jan 2007 01:31:23 -0000
@@ -403,6 +403,7 @@
     if (S_RESTLEN(p) < 0) {
         return Qnil;
     }
+    rb_kcode_set_option(regex);
     if (headonly) {
         ret = re_match(RREGEXP(regex)->ptr,
                        CURPTR(p), S_RESTLEN(p),
@@ -416,6 +417,7 @@
                         S_RESTLEN(p),
                         &(p->regs));
     }
+    rb_kcode_reset_option();
 
     if (ret == -2) rb_raise(ScanError, "regexp buffer overflow");
     if (ret < 0) {

--
青木峰郎

In This Thread