Bug #2696

rubyspec: StringIO#ungetc when passed [char] pads with \000 when the current position is after the end ERROR

Added by Yusuke Endoh about 2 years ago. Updated 9 months ago.

[ruby-dev:40271]
Status:Closed Start date:
Priority:Normal Due date:
Assignee:Nobuyoshi Nakada % Done:

100%

Category:-
Target version:-
ruby -v:nil

Description

stringio のメンテナのなかださん、もしくはまつもとさん
遠藤です。

stringio に関して、バッファ終端より先に pos を合わせた状態で
StringIO#ungetc を呼んだ時の挙動が 1.8 と 1.9 で違います。


# 1.8 では間が \0 で埋められる
$ ruby18 -rstringio -e '
io = StringIO.new("1234")
io.pos = 15
io.ungetc(?A)
p io.string
'
"1234\000\000\000\000\000\000\000\000\000\000A"


# 1.9 では例外になる
$ ./ruby -rstringio -e '
io = StringIO.new("1234")
io.pos = 15
io.ungetc(?A)
p io.string
'
-e:4:in `ungetc': index 14 out of string (IndexError)
        from -e:4:in `<main>'


r13261 が原因のようです。この挙動の変更を狙ったものではない
ような気がしますが、いかがでしょうか。

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Associated revisions

Revision 26588
Added by Yusuke Endoh about 2 years ago

* ext/stringio/stringio.c (strio_ungetc): pads with \000 when the current position is after the end. [ruby-dev:40271]

History

Updated by Yui NARUSE about 2 years ago

  • Priority changed from Low to Normal
  • ruby -v set to nil

Updated by ujihisa . about 2 years ago

  • Status changed from Open to Assigned
  • Assignee set to Nobuyoshi Nakada

Updated by Yusuke Endoh about 2 years ago

遠藤です。

2010年1月31日19:21 Yusuke ENDOH <mame@tsg.ne.jp>:
> stringio に関して、バッファ終端より先に pos を合わせた状態で
> StringIO#ungetc を呼んだ時の挙動が 1.8 と 1.9 で違います。
>
>
> # 1.8 では間が \0 で埋められる
> $ ruby18 -rstringio -e '
> io = StringIO.new("1234")
> io.pos = 15
> io.ungetc(?A)
> p io.string
> '
> "1234\000\000\000\000\000\000\000\000\000\000A"
>
>
> # 1.9 では例外になる
> $ ./ruby -rstringio -e '
> io = StringIO.new("1234")
> io.pos = 15
> io.ungetc(?A)
> p io.string
> '
> -e:4:in `ungetc': index 14 out of string (IndexError)
>        from -e:4:in `<main>'
>
>
> r13261 が原因のようです。この挙動の変更を狙ったものではない
> ような気がしますが、いかがでしょうか。


成瀬さんの監修のもと、パッチを書いてみました。
反対がなければコミットしてしまいます。

diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index f193c6e..faf974e 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -725,17 +725,26 @@ strio_ungetc(VALUE self, VALUE c)
 	    c = rb_str_conv_enc(c, enc2, enc);
 	}
     }
-    /* get logical position */
-    lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos;
-    for (;;) {
-	clen = rb_enc_mbclen(p, pend, enc);
-	if (p+clen >= pend) break;
-	p += clen;
-	lpos++;
+    if (RSTRING_LEN(ptr->string) < ptr->pos) {
+	long len = RSTRING_LEN(ptr->string);
+	rb_str_resize(ptr->string, ptr->pos - 1);
+	memset(RSTRING_PTR(ptr->string) + len, 0, ptr->pos - len - 1);
+	rb_str_concat(ptr->string, c);
+	ptr->pos--;
+    }
+    else {
+	/* get logical position */
+	lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos;
+	for (;;) {
+	    clen = rb_enc_mbclen(p, pend, enc);
+	    if (p+clen >= pend) break;
+	    p += clen;
+	    lpos++;
+	}
+	clen = p - RSTRING_PTR(ptr->string);
+	rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c);
+	ptr->pos = clen;
     }
-    clen = p - RSTRING_PTR(ptr->string);
-    rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c);
-    ptr->pos = clen;

     return Qnil;
 }

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Updated by Yusuke Endoh about 2 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100
This issue was solved with changeset r26588.
Yusuke, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

Also available in: Atom PDF