aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-06-19 09:44:26 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-06-19 09:44:26 +0900
commit28678997e40869f5591eae60edd9757334426ffb (patch)
tree76f6c6d8993e2b21cef090f1dcd030154bd1e018
parentd009e321a08d2ca401fceefa638e7e50872f5f54 (diff)
downloadruby-28678997e40869f5591eae60edd9757334426ffb.tar.gz
Preserve the string content at self-copying
* string.c (rb_str_init): preserve the embedded content when self-copying with a capacity. [Bug #15937]
-rw-r--r--string.c5
-rw-r--r--test/ruby/test_string.rb9
2 files changed, 13 insertions, 1 deletions
diff --git a/string.c b/string.c
index fdb7e4003c..e402a5a7aa 100644
--- a/string.c
+++ b/string.c
@@ -1331,6 +1331,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)
@@ -1611,7 +1612,9 @@ 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 (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 35f27c8b75..1d81d24dba 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -68,6 +68,15 @@ class TestString < Test::Unit::TestCase
assert_raise(FrozenError){ str.__send__(:initialize, encoding: 'euc-jp') }
assert_raise(FrozenError){ str.__send__(:initialize, 'abc', encoding: 'euc-jp') }
assert_raise(FrozenError){ str.__send__(:initialize, 'abc', capacity: 1000, encoding: 'euc-jp') }
+
+ str = S("")
+ assert_equal("mystring", str.__send__(:initialize, "mystring"))
+ str = S("mystring")
+ assert_equal("mystring", str.__send__(:initialize, str))
+ str = S("")
+ assert_equal("mystring", str.__send__(:initialize, "mystring", capacity: 1000))
+ str = S("mystring")
+ assert_equal("mystring", str.__send__(:initialize, str, capacity: 1000))
end
def test_initialize_nonstring