summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-08-26 16:16:39 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-08-26 16:16:39 +0000
commit6b7ebe835cdec0d6ad4f28e4587e55b5c73a0e93 (patch)
treecdfe508ea16af565b288c62bdd3659310bb6f8d5 /string.c
parent2b97b8e09028be1d03ed03980f2ad34db6349b9f (diff)
merge revision(s) 28678997e40869f5591eae60edd9757334426ffb,8797f48373dcfa3ff8e748667732dea8aea4347e: [Backport #15937]
Preserve the string content at self-copying * string.c (rb_str_init): preserve the embedded content when self-copying with a capacity. [Bug #15937] New buffer for shared string * string.c (rb_str_init): allocate new buffer if the string is shared. [Bug #15937] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_5@67769 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r--string.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/string.c b/string.c
index 9a81cefa72..5f8bd363fc 100644
--- a/string.c
+++ b/string.c
@@ -1297,6 +1297,7 @@ str_new_empty(VALUE str)
}
#define STR_BUF_MIN_SIZE 127
+STATIC_ASSERT(STR_BUF_MIN_SIZE, STR_BUF_MIN_SIZE > RSTRING_EMBED_LEN_MAX);
VALUE
rb_str_buf_new(long capa)
@@ -1579,7 +1580,18 @@ rb_str_init(int argc, VALUE *argv, VALUE str)
}
str_modifiable(str);
if (STR_EMBED_P(str)) { /* make noembed always */
- RSTRING(str)->as.heap.ptr = ALLOC_N(char, (size_t)capa + termlen);
+ char *new_ptr = ALLOC_N(char, (size_t)capa + termlen);
+ memcpy(new_ptr, RSTRING(str)->as.ary, RSTRING_EMBED_LEN_MAX + 1);
+ RSTRING(str)->as.heap.ptr = new_ptr;
+ }
+ else if (FL_TEST(str, STR_SHARED|STR_NOFREE)) {
+ const size_t size = (size_t)capa + termlen;
+ const char *const old_ptr = RSTRING_PTR(str);
+ const size_t osize = RSTRING(str)->as.heap.len + TERM_LEN(str);
+ char *new_ptr = ALLOC_N(char, (size_t)capa + termlen);
+ memcpy(new_ptr, old_ptr, osize < size ? osize : size);
+ FL_UNSET_RAW(str, STR_SHARED);
+ RSTRING(str)->as.heap.ptr = new_ptr;
}
else if (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
REALLOC_N(RSTRING(str)->as.heap.ptr, char, (size_t)capa + termlen);