[#24536] 「Rubyの落し方」 v.s. ruby_1_8 — akira yamada / やまだあきら <akira@...>

<URL:http://jp.rubyist.net/magazine/?0002-RubyCore>

40 messages 2004/10/20
[#24541] Re: 「Rubyの落し方」 v.s. ruby_1_8 — Yukihiro Matsumoto <matz@...> 2004/10/20

まつもと ゆきひろです

[#24599] 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/26

2004-10-20 (水) の 21:38 +0900 に Yukihiro Matsumoto さんは書きました:

[#24605] Re: 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/27

2004-10-26 (火) の 16:16 +0900 に akira yamada / やまだあきら さんは書きました:

[#24606] Re: 1.8.2 preview3? — Yukihiro Matsumoto <matz@...> 2004/10/27

まつもと ゆきひろです

[#24608] Re: 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/27

2004-10-27 (水) の 11:48 +0900 に Yukihiro Matsumoto さんは書きました:

[#24620] Re: 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/27

2004-10-27 (水) の 12:42 +0900 に akira yamada / やまだあきら さんは書きました:

[#24629] Re: 1.8.2 preview3? — Tanaka Akira <akr@...17n.org> 2004/10/29

In article <1098888819.9446.14.camel@rice.p.arika.org>,

[ruby-dev:24441] Re: IO#read with 1 argument dumps core

From: nobu@...
Date: 2004-10-07 03:46:41 UTC
List: ruby-dev #24441
なかだです。

At Mon, 4 Oct 2004 17:50:20 +0900,
Yukihiro Matsumoto wrote in [ruby-dev:24430]:
> |[ruby-dev:24412]だと、read中に例外で抜けたときにfreezeされたま
> |まになってしまうので、こうするのはどうでしょうか。
> 
> rb_io_freadは例外を発生させないので、割り込みのことですかね。
> まあ、基本的なアイディアは有効だと思います。コミットしてくだ
> さい。
> 
> # なるほどshared stringを使うのか。

送った後で気づいたんですが、単純にあれだけではまずそうです。

  buf = rb_str_new4(str);
  ptr = RSTRING(buf)->ptr;
  ...
  return str;

のような場合、

(1) bufが最適化によって消されている場合、途中でstrが変更される
    と、shared stringはGCから保護されない
    →dangling pointer

(2) (each_objectなどによって捜し出されて)bufからさらに共有する
    Stringが作られた場合、rb_io_fread後はそのptrはfreezeされて
    いないStringと共有されてしまう
    →dangling pointer または double free

(3) rb_str_shared_replace()は最初にrb_str_modify()を呼ぶため、
    直後に解放するはずのptrを複製している
    →バッファを引数で指定する意味がない


Index: intern.h
===================================================================
RCS file: /cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.156
diff -U2 -p -d -r1.156 intern.h
--- intern.h	6 Oct 2004 07:40:04 -0000	1.156
+++ intern.h	7 Oct 2004 03:37:00 -0000
@@ -415,4 +415,5 @@ VALUE rb_str_buf_append _((VALUE, VALUE)
 VALUE rb_str_buf_cat _((VALUE, const char*, long));
 VALUE rb_str_buf_cat2 _((VALUE, const char*));
+void rb_str_shared_replace _((VALUE, VALUE));
 VALUE rb_obj_as_string _((VALUE));
 VALUE rb_check_string_type _((VALUE));
Index: io.c
===================================================================
RCS file: /cvs/ruby/src/ruby/io.c,v
retrieving revision 1.299
diff -U2 -p -d -r1.299 io.c
--- io.c	6 Oct 2004 15:10:43 -0000	1.299
+++ io.c	7 Oct 2004 03:30:12 -0000
@@ -1172,5 +1172,5 @@ io_read(argc, argv, io)
     OpenFile *fptr;
     long n, len;
-    VALUE length, str;
+    VALUE length, str, buf;
 
     rb_scan_args(argc, argv, "02", &length, &str);
@@ -1196,10 +1196,10 @@ io_read(argc, argv, io)
 	rb_str_resize(str,len);
     }
-    FL_SET(str, FL_FREEZE);
     if (len == 0) return str;
 
+    buf = rb_str_new4(str);
+    RBASIC(buf)->klass = 0;
     READ_CHECK(fptr->f);
-    n = rb_io_fread(RSTRING(str)->ptr, len, fptr->f);
-    FL_UNSET(str, FL_FREEZE);
+    n = rb_io_fread(RSTRING(buf)->ptr, len, fptr->f);
     if (n == 0) {
 	rb_str_resize(str,0);
@@ -1208,7 +1208,9 @@ io_read(argc, argv, io)
 	if (len > 0) rb_sys_fail(fptr->path);
     }
+    rb_str_shared_replace(str, buf);
     RSTRING(str)->len = n;
     RSTRING(str)->ptr[n] = '\0';
     OBJ_TAINT(str);
+    rb_gc_force_recycle(buf);
 
     return str;
@@ -4155,5 +4157,6 @@ next_argv()
 	if (RARRAY(rb_argv)->len > 0) {
 	    filename = rb_ary_shift(rb_argv);
-	    fn = StringValuePtr(filename);
+	    filename = rb_str_new4(StringValue(filename));
+	    fn = RSTRING(filename)->ptr;
 	    if (strlen(fn) == 1 && fn[0] == '-') {
 		current_file = rb_stdin;
@@ -4168,5 +4171,4 @@ next_argv()
 		if (ruby_inplace_mode) {
 		    struct stat st, st2;
-		    VALUE str;
 		    FILE *fw;
 
@@ -4176,5 +4178,5 @@ next_argv()
 		    fstat(fileno(fr), &st);
 		    if (*ruby_inplace_mode) {
-			str = rb_str_new2(fn);
+			VALUE str = rb_str_new2(fn);
 #ifdef NO_LONG_FNAME
                         ruby_add_suffix(str, ruby_inplace_mode);
@@ -4182,4 +4184,5 @@ next_argv()
 			rb_str_cat2(str, ruby_inplace_mode);
 #endif
+			OBJ_FREEZE(str);
 #ifdef NO_SAFE_RENAME
 			(void)fclose(fr);
Index: string.c
===================================================================
RCS file: /cvs/ruby/src/ruby/string.c,v
retrieving revision 1.204
diff -U2 -p -d -r1.204 string.c
--- string.c	6 Oct 2004 07:40:03 -0000	1.204
+++ string.c	7 Oct 2004 03:40:01 -0000
@@ -37,4 +37,6 @@ VALUE rb_cString;
 VALUE rb_fs;
 
+static int str_independent _((VALUE));
+
 static VALUE str_alloc _((VALUE));
 static VALUE
@@ -232,11 +234,10 @@ rb_str_to_str(str)
 }
 
-static void
+void
 rb_str_shared_replace(str, str2)
     VALUE str, str2;
 {
     if (str == str2) return;
-    rb_str_modify(str);
-    if (!FL_TEST(str, ELTS_SHARED)) free(RSTRING(str)->ptr);
+    if (str_independent(str)) free(RSTRING(str)->ptr);
     if (NIL_P(str2)) {
 	RSTRING(str)->ptr = 0;


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

In This Thread

Prev Next