summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ext/-test-/string/cstr.c23
-rw-r--r--string.c3
-rw-r--r--test/-ext-/string/test_cstr.rb6
4 files changed, 36 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index aee069a8090..f0bfe7d829b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon May 30 16:20:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_fill_term): return new pointer reallocated by
+ filling terminator.
+
Mon May 30 14:54:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/stringio/stringio.c (enc_subseq): share the return value and
diff --git a/ext/-test-/string/cstr.c b/ext/-test-/string/cstr.c
index 9bd33a344e0..fc47d5206f4 100644
--- a/ext/-test-/string/cstr.c
+++ b/ext/-test-/string/cstr.c
@@ -50,6 +50,28 @@ bug_str_cstr_term_char(VALUE str)
}
static VALUE
+bug_str_unterminated_substring(VALUE str, VALUE vbeg, VALUE vlen)
+{
+ long beg = NUM2LONG(vbeg);
+ long len = NUM2LONG(vlen);
+ rb_str_modify(str);
+ if (len < 0) rb_raise(rb_eArgError, "negative length: %ld", len);
+ if (RSTRING_LEN(str) < beg) rb_raise(rb_eIndexError, "beg: %ld", beg);
+ if (RSTRING_LEN(str) < beg + len) rb_raise(rb_eIndexError, "end: %ld", beg + len);
+ str = rb_str_new_shared(str);
+ if (STR_EMBED_P(str)) {
+ RSTRING(str)->basic.flags &= ~RSTRING_EMBED_LEN_MASK;
+ RSTRING(str)->basic.flags |= len << RSTRING_EMBED_LEN_SHIFT;
+ memmove(RSTRING(str)->as.ary, RSTRING(str)->as.ary + beg, len);
+ }
+ else {
+ RSTRING(str)->as.heap.ptr += beg;
+ RSTRING(str)->as.heap.len = len;
+ }
+ return str;
+}
+
+static VALUE
bug_str_s_cstr_term(VALUE self, VALUE str)
{
Check_Type(str, T_STRING);
@@ -114,6 +136,7 @@ Init_cstr(VALUE klass)
rb_define_method(klass, "cstr_term", bug_str_cstr_term, 0);
rb_define_method(klass, "cstr_unterm", bug_str_cstr_unterm, 1);
rb_define_method(klass, "cstr_term_char", bug_str_cstr_term_char, 0);
+ rb_define_method(klass, "unterminated_substring", bug_str_unterminated_substring, 2);
rb_define_singleton_method(klass, "cstr_term", bug_str_s_cstr_term, 1);
rb_define_singleton_method(klass, "cstr_unterm", bug_str_s_cstr_unterm, 2);
rb_define_singleton_method(klass, "cstr_term_char", bug_str_s_cstr_term_char, 1);
diff --git a/string.c b/string.c
index 97831e569a9..c3fb9b22778 100644
--- a/string.c
+++ b/string.c
@@ -2012,8 +2012,9 @@ str_fill_term(VALUE str, char *s, long len, int termlen)
}
else {
TERM_FILL(s + len, termlen);
+ return s;
}
- return s;
+ return RSTRING_PTR(str);
}
char *
diff --git a/test/-ext-/string/test_cstr.rb b/test/-ext-/string/test_cstr.rb
index 35b5fe59316..2083016db28 100644
--- a/test/-ext-/string/test_cstr.rb
+++ b/test/-ext-/string/test_cstr.rb
@@ -18,6 +18,12 @@ class Test_StringCStr < Test::Unit::TestCase
assert_equal(0, s.cstr_term, Bug4319)
end
+ def test_shared
+ s = Bug::String.new("abcdef")*5
+ s = s.unterminated_substring(0, 29)
+ assert_equal(0, s.cstr_term, Bug4319)
+ end
+
def test_frozen
s0 = Bug::String.new("abcdefgh"*8)