summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorngoto <ngoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-01 17:32:21 +0000
committerngoto <ngoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-01 17:32:21 +0000
commit61f2ee0d90e017e387c537bba6322075fbf4884c (patch)
tree5399340cfc19d43eb61f9c0cdeb254f49537766f
parent6fee4909c8f58c83ae36a46857579cc5cd8c944f (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
-rw-r--r--ChangeLog7
-rw-r--r--string.c25
2 files changed, 29 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 100ba42d51..6d20e34d70 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Sat Jul 2 02:22:22 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * 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]
+
Fri Jul 1 20:20:20 2016 Naohisa Goto <ngotogenome@gmail.com>
* string.c: Specify termlen as far as possible.
diff --git a/string.c b/string.c
index 55d87bb9a9..a755785b96 100644
--- a/string.c
+++ b/string.c
@@ -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;
}