diff options
author | ngoto <ngoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-07-01 17:32:21 +0000 |
---|---|---|
committer | ngoto <ngoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-07-01 17:32:21 +0000 |
commit | 61f2ee0d90e017e387c537bba6322075fbf4884c (patch) | |
tree | 5399340cfc19d43eb61f9c0cdeb254f49537766f /string.c | |
parent | 6fee4909c8f58c83ae36a46857579cc5cd8c944f (diff) |
* string.c (str_fill_term): When termlen increases, re-allocation
of memory for termlen should always be needed.
In this fix, if possible, decrease capa instead of realloc.
[Bug #12536] [ruby-dev:49699]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55557 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r-- | string.c | 25 |
1 files changed, 22 insertions, 3 deletions
@@ -2029,17 +2029,36 @@ str_null_char(const char *s, long len, const int minlen, rb_encoding *enc) static char * str_fill_term(VALUE str, char *s, long len, int termlen) { - long capa = rb_str_capacity(str) + 1; + long capa = rb_str_capacity(str); + /* This function could be called during the encoding changing procedure. + * If so, the termlen may be different from current TERM_LEN(str). + */ + const int oldtermlen = TERM_LEN(str); - if (capa < len + termlen) { + if (capa < len + termlen - 1) { /* assumes oldtermlen is 1 here */ rb_check_lockedtmp(str); str_make_independent_expand(str, len, 0L, termlen); } else if (str_dependent_p(str)) { - if (!zero_filled(s + len, termlen)) + if ((termlen > oldtermlen) || !zero_filled(s + len, termlen)) str_make_independent_expand(str, len, 0L, termlen); } else { + if (termlen > oldtermlen) { + if (!STR_EMBED_P(str)) { + const int d = termlen - oldtermlen; + if (capa > len + d) { + /* decrease capa for the new termlen */ + capa -= d; + assert(capa >= 1); + assert(!FL_TEST((str), STR_SHARED)); + RSTRING(str)->as.heap.aux.capa = capa; + } else { + assert(capa >= len); + RESIZE_CAPA_TERM(str, capa, termlen); + } + } + } TERM_FILL(s + len, termlen); return s; } |