From: nobu@... Date: 2004-10-26T21:50:18+09:00 Subject: [ruby-dev:24601] Re: unpack("p") dumps core なかだです。 At Tue, 26 Oct 2004 18:21:30 +0900, Yukihiro Matsumoto wrote in [ruby-dev:24600]: > |str_independent()ではSTR_ASSOCを見ていないので(STR_NO_ORIGから > |変更されたとき以来?)、rb_str_modify()ではSTR_ASSOCがクリアされ > |ていないようです。また、gsub!やsucc!ではstr_independent()によっ > |てptrをfreeしているので、["abc"].pack("p").gsub!(/.*/, '')など > |とするとメモリリークしそうです。 > > RESIZE_CAPA()でSTR_ASSOCを見ることで問題は解決するような気が > します。 aux.capaを変更 == aux.sharedは無効、ということですね。他のcapa を変更しているところはSTR_ASSOCをクリアしているようです。 > |# というか、str_gsub()のbufって例外のときにも大丈夫? > > 気にはなっているんですが。 Stringをバッファにするということでどうでしょうか。 Index: string.c =================================================================== RCS file: /cvs/ruby/src/ruby/string.c,v retrieving revision 1.209 diff -U2 -p -d -r1.209 string.c --- string.c 21 Oct 2004 15:20:41 -0000 1.209 +++ string.c 26 Oct 2004 12:46:05 -0000 @@ -33,8 +33,22 @@ VALUE rb_cString; REALLOC_N(RSTRING(str)->ptr, char, (capacity)+1);\ RSTRING(str)->aux.capa = (capacity);\ + FL_UNSET(str, STR_ASSOC|ELTS_SHARED);\ } while (0) VALUE rb_fs; +static int str_independent _((VALUE)); + +static inline void +str_mod_check(s, p, len) + VALUE s; + char *p; + long len; +{ + if (RSTRING(s)->ptr != p || RSTRING(s)->len != len) { + rb_raise(rb_eRuntimeError, "string modified"); + } +} + static VALUE str_alloc _((VALUE)); static VALUE @@ -2009,5 +2023,5 @@ str_gsub(argc, argv, str, bang) int bang; { - VALUE pat, val, repl, match; + VALUE pat, val, repl, match, dest; struct re_registers *regs; long beg, n; @@ -2038,5 +2052,6 @@ str_gsub(argc, argv, str, bang) blen = RSTRING(str)->len + 30; /* len + margin */ - buf = ALLOC_N(char, blen); + dest = rb_str_new5(str, 0, blen); + buf = RSTRING(dest)->ptr; bp = buf; cp = RSTRING(str)->ptr; @@ -2049,7 +2064,5 @@ str_gsub(argc, argv, str, bang) rb_match_busy(match); val = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match))); - if (RSTRING(str)->ptr == buf) { - rb_raise(rb_eRuntimeError, "gsub reentered"); - } + str_mod_check(dest, buf, blen); rb_backref_set(match); } @@ -2062,5 +2075,7 @@ str_gsub(argc, argv, str, bang) while (blen < len) blen *= 2; len = bp - buf; - REALLOC_N(buf, char, blen); + RESIZE_CAPA(dest, blen); + RSTRING(dest)->len = blen; + buf = RSTRING(dest)->ptr; bp = buf + len; } @@ -2088,6 +2103,8 @@ str_gsub(argc, argv, str, bang) if (RSTRING(str)->len > offset) { len = bp - buf; - if (blen - len < RSTRING(str)->len - offset + 1) { - REALLOC_N(buf, char, len + RSTRING(str)->len - offset + 1); + if (blen - len < RSTRING(str)->len - offset) { + blen = len + RSTRING(str)->len - offset; + RESIZE_CAPA(dest, blen); + buf = RSTRING(dest)->ptr; bp = buf + len; } @@ -2096,4 +2113,5 @@ str_gsub(argc, argv, str, bang) } rb_backref_set(match); + *bp = '\0'; if (bang) { if (str_independent(str)) { @@ -2101,15 +2119,14 @@ str_gsub(argc, argv, str, bang) } FL_UNSET(str, ELTS_SHARED|STR_ASSOC); + RSTRING(str)->ptr = buf; + RSTRING(str)->aux.capa = blen; + RSTRING(dest)->ptr = 0; + RSTRING(dest)->len = 0; } else { - VALUE dup = str_alloc(rb_obj_class(str)); - - OBJ_INFECT(dup, str); - str = dup; + OBJ_INFECT(dest, str); + str = dest; } - RSTRING(str)->ptr = buf; - RSTRING(str)->len = len = bp - buf; - RSTRING(str)->ptr[len] = '\0'; - RSTRING(str)->aux.capa = len; + RSTRING(str)->len = bp - buf; if (tainted) OBJ_TAINT(str); @@ -3591,16 +3608,4 @@ rb_f_split(argc, argv) { return rb_str_split_m(argc, argv, uscore_get()); -} - - -static inline void -str_mod_check(s, p, len) - VALUE s; - char *p; - long len; -{ - if (RSTRING(s)->ptr != p || RSTRING(s)->len != len) { - rb_raise(rb_eRuntimeError, "string modified"); - } } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦