StringScanner#scan BUG?

e$B$H$_$?$G$9!#e(B

Ruby 1.8.5 e$B$G<!$N%3!<%I$r<B9T$9$k$H!"e(B$KCODE=“NONE”
e$B$+$D@55,I=8=$N%U%ie(B
e$B%0$,e(B e, s, u e$B$N>l9g$K!“e(B"a:b” e$B$rJV$7$^$9!#e(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:] e$B$re(B [^:\x01] e$B$K$9$k$HH/@8$7$^$;$s!#4|BT$I$*$je(B “a”
e$B$rJV$7$^$9!#e(B

e$B$O$8$a$Oe(B Ruby
e$BK\BN$N@55,I=8=$N%P%0$+$H;W$C$?$N$G$9$,!"e(BStringScanner e$B0Je(B
e$B30$G$OH/@8$7$J$$$h$&$G$9!#e(B

e$B@DLZ$G$9!#$9$_$^$;$s!"$9$C$+$j8+Mn$H$7$F$^$7$?!#e(B

In mail “[ruby-dev:29914] StringScanner#scan BUG?”
e$B$H$_$?$^$5$R$me(B [email protected] wrote:

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:] e$B$re(B [^:\x01] e$B$K$9$k$HH/@8$7$^$;$s!#4|BT$I$*$je(B “a” e$B$rJV$7$^$9!#e(B

e$B$O$8$a$Oe(B Ruby e$BK\BN$N@55,I=8=$N%P%0$+$H;W$C$?$N$G$9$,!"e(BStringScanner e$B0Je(B
e$B30$G$OH/@8$7$J$$$h$&$G$9!#e(B

strscan.c e$B$Ge(B kcode_set_option
e$B$r8F$s$G$J$+$C$?$N$,860x$G$7$?!#e(B

e$B0J2<$N%Q%C%A$G=$@5$G$-$k$N$G$9$,!"e(B1.8
e$B%V%i%s%A$K%3%_%C%H$7$F$h$$$G$7$g$&$+!)e(B
extern e$B4X?t$,e(B 2 e$B$DA}$($^$9!#e(B

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) {

 問題ありません。お願いします。

At Sun, 7 Jan 2007 10:34:15 +0900,
Minero A. wrote:

[^\x01:] ã‚’ [^:\x01] にすると発生しません。期待どおり “a” を返します。

はじめは Ruby 本体の正規表現のバグかと思ったのですが、StringScanner 以
外では発生しないようです。

strscan.c で kcode_set_option ã‚’å‘¼ã‚“ã§ãªã‹ã£ãŸã®ãŒåŽŸå› ã§ã—ãŸã€‚

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


/
/__ __ Akinori.org / MUSHA.org
/ ) ) ) ) / FreeBSD.org / Ruby-lang.org
Akinori MUSHA aka / (_ / ( (__( @ iDaemons.org / and.or.jp

“Different eyes see different things,
Different hearts beat on different strings –
But there are times for you and me when all such things agree”