diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | ext/-test-/string/modify.c | 8 | ||||
-rw-r--r-- | include/ruby/intern.h | 1 | ||||
-rw-r--r-- | string.c | 16 |
4 files changed, 25 insertions, 4 deletions
@@ -1,3 +1,7 @@ +Wed Feb 8 22:29:59 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * string.c (rb_str_modify_expand): fix memory leak. + Wed Feb 8 10:58:45 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> * ext/readline/readline.c (readline_attempted_completion_function): diff --git a/ext/-test-/string/modify.c b/ext/-test-/string/modify.c index a6930051b6..ddd2efd8f0 100644 --- a/ext/-test-/string/modify.c +++ b/ext/-test-/string/modify.c @@ -7,8 +7,16 @@ bug_str_modify(VALUE str) return str; } +VALUE +bug_str_modify_expand(VALUE str, VALUE expand) +{ + rb_str_modify_expand(str, NUM2LONG(expand)); + return str; +} + void Init_modify(VALUE klass) { rb_define_method(klass, "modify!", bug_str_modify, 0); + rb_define_method(klass, "modify_expand!", bug_str_modify_expand, 1); } diff --git a/include/ruby/intern.h b/include/ruby/intern.h index dae61a7812..50451f35b3 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -691,6 +691,7 @@ long rb_str_sublen(VALUE, long); VALUE rb_str_substr(VALUE, long, long); VALUE rb_str_subseq(VALUE, long, long); void rb_str_modify(VALUE); +void rb_str_modify_expand(VALUE, long); VALUE rb_str_freeze(VALUE); void rb_str_set_len(VALUE, long); VALUE rb_str_resize(VALUE, long); @@ -1328,12 +1328,20 @@ rb_str_modify_expand(VALUE str, long expand) if (expand < 0) { rb_raise(rb_eArgError, "negative expanding string size"); } - if (!str_independent(str) || - (expand > 0 && - (!STR_EMBED_P(str) || - RSTRING_LEN(str) + expand > RSTRING_EMBED_LEN_MAX))) { + if (!str_independent(str)) { str_make_independent_expand(str, expand); } + else if (expand > 0) { + long len = RSTRING_LEN(str); + long capa = len + expand; + if (!STR_EMBED_P(str)) { + REALLOC_N(RSTRING(str)->as.heap.ptr, char, capa+1); + RSTRING(str)->as.heap.aux.capa = capa; + } + else if (capa > RSTRING_EMBED_LEN_MAX) { + str_make_independent_expand(str, expand); + } + } ENC_CODERANGE_CLEAR(str); } |