From: nobu@... Date: 2004-10-29T12:17:07+09:00 Subject: [ruby-dev:24632] Re: temporarily frozen string causes core dump なかだです。 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はできる。 中田 伸悦