[#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:24632] Re: temporarily frozen string causes core dump

From: nobu@...
Date: 2004-10-29 03:17:07 UTC
List: ruby-dev #24632
なかだです。

At Thu, 21 Oct 2004 08:33:18 +0900,
nobu@ruby-lang.org wrote in [ruby-dev:24552]:
> ということで、今考えているのが
> 
>     buf = rb_str_new4(str);
>     RBASIC(buf)->klass = 0;
>     rb_str_shared_replace(str, Qnil);
>     /* 読み込み */
>     rb_str_shared_replace(str, buf);

これだとread_all()でresizeするところでエラーになるので、必要な
のは

  a) 元のStringからはバッファをアクセスできなくした上で
  b) 元のStringのptr,lenを使用する
  c) freezeされていない
  d) each_objectで見えない

T_STRINGなオブジェクトということになります。


Index: intern.h
===================================================================
RCS file: /cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.157
diff -U2 -p -d -r1.157 intern.h
--- intern.h	27 Oct 2004 09:29:25 -0000	1.157
+++ intern.h	29 Oct 2004 03:09:25 -0000
@@ -416,4 +416,6 @@ 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_str_shared_buffer _((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.311
diff -U2 -p -d -r1.311 io.c
--- io.c	29 Oct 2004 01:06:36 -0000	1.311
+++ io.c	29 Oct 2004 03:05:53 -0000
@@ -942,5 +942,5 @@ rb_io_fread(ptr, len, f)
 	    if ((n -= c) <= 0) break;
 	}
-        rb_thread_wait_fd(fileno(f));
+	rb_thread_wait_fd(fileno(f));
 	TRAP_BEG;
 	c = getc(f);
@@ -1015,4 +1015,5 @@ read_all(fptr, siz, str)
     long bytes = 0;
     long n;
+    VALUE buf;
 
     if (siz == 0) siz = BUFSIZ;
@@ -1024,11 +1025,9 @@ read_all(fptr, siz, str)
 	rb_str_resize(str, siz);
     }
+    buf = rb_str_shared_buffer(str);
     for (;;) {
-	FL_SET(str, FL_FREEZE);
 	READ_CHECK(fptr->f);
-	n = rb_io_fread(RSTRING(str)->ptr+bytes, siz-bytes, fptr->f);
-	FL_UNSET(str, FL_FREEZE);
+	n = rb_io_fread(RSTRING(buf)->ptr+bytes, siz-bytes, fptr->f);
 	if (n == 0 && bytes == 0) {
-	    rb_str_resize(str,0);
 	    if (!fptr->f) break;
 	    if (feof(fptr->f)) break;
@@ -1039,6 +1038,7 @@ read_all(fptr, siz, str)
 	if (bytes < siz) break;
 	siz += BUFSIZ;
-	rb_str_resize(str, siz);
+	rb_str_resize(buf, siz);
     }
+    rb_str_shared_replace(str, buf);
     if (bytes != siz) rb_str_resize(str, bytes);
 
@@ -1106,5 +1106,5 @@ io_readpartial(argc, argv, io)
 {
     OpenFile *fptr;
-    VALUE length, str;
+    VALUE length, str, buf;
     long n, len;
 
@@ -1131,29 +1131,30 @@ io_readpartial(argc, argv, io)
 	return str;
 
+    buf = rb_str_shared_buffer(str);
+
     READ_CHECK(fptr->f);
-    if (RSTRING(str)->len != len) {
+    if (RSTRING(buf)->len != len) {
       modified:
 	rb_raise(rb_eRuntimeError, "buffer string modified");
     }
-    n = read_buffered_data(RSTRING(str)->ptr, len, fptr->f);
+    n = read_buffered_data(RSTRING(buf)->ptr, len, fptr->f);
     if (n <= 0) {
-      again:
-	if (RSTRING(str)->len != len) goto modified;
-        TRAP_BEG;
-        n = read(fileno(fptr->f), RSTRING(str)->ptr, len);
-        TRAP_END;
-        if (n < 0) {
-            if (rb_io_wait_readable(fileno(fptr->f)))
-                goto again;
-            rb_str_resize(str, 0);
-            rb_sys_fail(fptr->path);
-        }
+	for (;;) {
+	    if (RSTRING(buf)->len != len) goto modified;
+	    TRAP_BEG;
+	    n = read(fileno(fptr->f), RSTRING(buf)->ptr, len);
+	    TRAP_END;
+	    if (n >= 0) break;
+	    if (!rb_io_wait_readable(fileno(fptr->f)))
+		rb_sys_fail(fptr->path);
+	}
     }
-    rb_str_resize(str, n);
 
     if (n == 0)
         rb_eof_error();
-    else
-        return str;
+
+    rb_str_shared_replace(str, buf);
+    rb_str_resize(str, n);
+    return str;
 }
 
@@ -1180,5 +1181,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);
@@ -1206,8 +1207,7 @@ io_read(argc, argv, io)
     if (len == 0) return str;
 
-    FL_SET(str, FL_FREEZE);
+    buf = rb_str_shared_buffer(str);
     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);
@@ -1216,4 +1216,5 @@ 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';
@@ -4187,5 +4188,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;
@@ -4200,5 +4202,4 @@ next_argv()
 		if (ruby_inplace_mode) {
 		    struct stat st, st2;
-		    VALUE str;
 		    FILE *fw;
 
@@ -4208,10 +4209,11 @@ 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);
+			ruby_add_suffix(str, ruby_inplace_mode);
 #else
 			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.212
diff -U2 -p -d -r1.212 string.c
--- string.c	27 Oct 2004 15:22:50 -0000	1.212
+++ string.c	29 Oct 2004 03:08:38 -0000
@@ -39,4 +39,6 @@ VALUE rb_cString;
 VALUE rb_fs;
 
+static int str_independent _((VALUE));
+
 static inline void
 str_mod_check(s, p, len)
@@ -245,11 +247,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;
@@ -274,4 +275,14 @@ rb_str_shared_replace(str, str2)
     FL_UNSET(str2, STR_NOCAPA);
     if (OBJ_TAINTED(str2)) OBJ_TAINT(str);
+}
+
+VALUE
+rb_str_shared_buffer(orig)
+    VALUE orig;
+{
+    VALUE str;
+    rb_str_modify(orig);
+    rb_str_shared_replace(str = str_alloc(0), orig);
+    return str;
 }
 


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

In This Thread