summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-02-19 06:33:07 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-02-19 06:33:07 +0000
commitd43dcc67ceebe102a2c39fbe261c89e50b75f7a0 (patch)
tree84d35882eb5f931bf1f256dd20bcb2311ebb8722
parent490165e5e39c33b1f99cb0fac5db6765b5b9f38a (diff)
merge revision(s) 49405-49408:
* string.c (str_make_independent_expand): terminate String when moved from heap to embedded. [Fix GH-821]. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@49644 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog5
-rw-r--r--string.c32
-rw-r--r--test/-ext-/string/test_cstr.rb20
-rw-r--r--version.h2
4 files changed, 48 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 676c0edc20..0eec296dcf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Thu Feb 19 15:32:26 2015 Dave Stevens <dave@crowdlab.com>
+
+ * string.c (str_make_independent_expand): terminate String when
+ moved from heap to embedded. [Fix GH-821].
+
Thu Feb 19 13:35:21 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/sdbm/_sdbm.c: include ruby/ruby.h for PRIdPTRDIFF when a
diff --git a/string.c b/string.c
index 0fae07d938..e857e3c35f 100644
--- a/string.c
+++ b/string.c
@@ -98,6 +98,9 @@ VALUE rb_cSymbol;
#define RESIZE_CAPA(str,capacity) do {\
const int termlen = TERM_LEN(str);\
+ RESIZE_CAPA_TERM(str,capacity,termlen);\
+} while (0)
+#define RESIZE_CAPA_TERM(str,capacity,termlen) do {\
if (STR_EMBED_P(str)) {\
if ((capacity) > RSTRING_EMBED_LEN_MAX) {\
char *const tmp = ALLOC_N(char, (capacity)+termlen);\
@@ -1589,10 +1592,11 @@ str_make_independent_expand(VALUE str, long expand)
if (len > capa) len = capa;
- if (capa <= RSTRING_EMBED_LEN_MAX && !STR_EMBED_P(str)) {
+ if (capa + termlen - 1 <= RSTRING_EMBED_LEN_MAX && !STR_EMBED_P(str)) {
ptr = RSTRING(str)->as.heap.ptr;
STR_SET_EMBED(str);
memcpy(RSTRING(str)->as.ary, ptr, len);
+ TERM_FILL(RSTRING(str)->as.ary + len, termlen);
STR_SET_EMBED_LEN(str, len);
return;
}
@@ -2166,23 +2170,30 @@ rb_str_resize(VALUE str, long len)
static VALUE
str_buf_cat(VALUE str, const char *ptr, long len)
{
- long capa, total, off = -1;
+ long capa, total, olen, off = -1;
+ char *sptr;
+ const int termlen = TERM_LEN(str);
- if (ptr >= RSTRING_PTR(str) && ptr <= RSTRING_END(str)) {
- off = ptr - RSTRING_PTR(str);
+ RSTRING_GETMEM(str, sptr, olen);
+ if (ptr >= sptr && ptr <= sptr + olen) {
+ off = ptr - sptr;
}
rb_str_modify(str);
if (len == 0) return 0;
if (STR_EMBED_P(str)) {
capa = RSTRING_EMBED_LEN_MAX;
+ sptr = RSTRING(str)->as.ary;
+ olen = RSTRING_EMBED_LEN(str);
}
else {
capa = RSTRING(str)->as.heap.aux.capa;
+ sptr = RSTRING(str)->as.heap.ptr;
+ olen = RSTRING(str)->as.heap.len;
}
- if (RSTRING_LEN(str) >= LONG_MAX - len) {
+ if (olen >= LONG_MAX - len) {
rb_raise(rb_eArgError, "string sizes too big");
}
- total = RSTRING_LEN(str)+len;
+ total = olen + len;
if (capa <= total) {
while (total > capa) {
if (capa > LONG_MAX / 2) {
@@ -2191,14 +2202,15 @@ str_buf_cat(VALUE str, const char *ptr, long len)
}
capa = 2 * capa;
}
- RESIZE_CAPA(str, capa);
+ RESIZE_CAPA_TERM(str, capa, termlen);
+ sptr = RSTRING_PTR(str);
}
if (off != -1) {
- ptr = RSTRING_PTR(str) + off;
+ ptr = sptr + off;
}
- memcpy(RSTRING_PTR(str) + RSTRING_LEN(str), ptr, len);
+ memcpy(sptr + olen, ptr, len);
STR_SET_LEN(str, total);
- RSTRING_PTR(str)[total] = '\0'; /* sentinel */
+ TERM_FILL(sptr + total, termlen); /* sentinel */
return str;
}
diff --git a/test/-ext-/string/test_cstr.rb b/test/-ext-/string/test_cstr.rb
index 6f2fdef3d4..272e090955 100644
--- a/test/-ext-/string/test_cstr.rb
+++ b/test/-ext-/string/test_cstr.rb
@@ -86,6 +86,26 @@ class Test_StringCStr < Test::Unit::TestCase
}
end
+ def test_embedded_from_heap
+ gh821 = "[GH-821]"
+ embedded_string = "abcdefghi"
+ string = embedded_string.gsub("efg", "123")
+ {}[string] = 1
+ non_terminated = "#{string}#{nil}"
+ assert_nil(Bug::String.cstr_term_char(non_terminated), gh821)
+
+ result = {}
+ WCHARS.map do |enc|
+ embedded_string = "ab".encode(enc)
+ string = embedded_string.gsub("b".encode(enc), "1".encode(enc))
+ {}[string] = 1
+ non_terminated = "#{string}#{nil}"
+ c = Bug::String.cstr_term_char(non_terminated)
+ result[enc] = c if c
+ end
+ assert_empty(result, gh821)
+ end
+
def assert_wchars_term_char(str)
result = {}
WCHARS.map do |enc|
diff --git a/version.h b/version.h
index 00419b19c4..088f1a924c 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.2.0"
#define RUBY_RELEASE_DATE "2015-02-19"
-#define RUBY_PATCHLEVEL 54
+#define RUBY_PATCHLEVEL 55
#define RUBY_RELEASE_YEAR 2015
#define RUBY_RELEASE_MONTH 2