diff options
author | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-02-19 06:33:07 +0000 |
---|---|---|
committer | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-02-19 06:33:07 +0000 |
commit | d43dcc67ceebe102a2c39fbe261c89e50b75f7a0 (patch) | |
tree | 84d35882eb5f931bf1f256dd20bcb2311ebb8722 | |
parent | 490165e5e39c33b1f99cb0fac5db6765b5b9f38a (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-- | ChangeLog | 5 | ||||
-rw-r--r-- | string.c | 32 | ||||
-rw-r--r-- | test/-ext-/string/test_cstr.rb | 20 | ||||
-rw-r--r-- | version.h | 2 |
4 files changed, 48 insertions, 11 deletions
@@ -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 @@ -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| @@ -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 |