diff options
-rw-r--r-- | ext/-test-/string/depend | 11 | ||||
-rw-r--r-- | ext/-test-/string/rb_str_dup.c | 35 | ||||
-rw-r--r-- | string.c | 11 | ||||
-rw-r--r-- | test/-ext-/string/test_rb_str_dup.rb | 16 | ||||
-rw-r--r-- | test/ruby/test_string.rb | 9 | ||||
-rw-r--r-- | version.h | 2 |
6 files changed, 79 insertions, 5 deletions
diff --git a/ext/-test-/string/depend b/ext/-test-/string/depend index 8e7ee2a55a..71e995a523 100644 --- a/ext/-test-/string/depend +++ b/ext/-test-/string/depend @@ -173,6 +173,17 @@ qsort.o: $(hdrdir)/ruby/subst.h qsort.o: $(hdrdir)/ruby/util.h qsort.o: $(top_srcdir)/include/ruby.h qsort.o: qsort.c +rb_str_dup.o: $(RUBY_EXTCONF_H) +rb_str_dup.o: $(arch_hdrdir)/ruby/config.h +rb_str_dup.o: $(hdrdir)/ruby.h +rb_str_dup.o: $(hdrdir)/ruby/backward.h +rb_str_dup.o: $(hdrdir)/ruby/defines.h +rb_str_dup.o: $(hdrdir)/ruby/intern.h +rb_str_dup.o: $(hdrdir)/ruby/missing.h +rb_str_dup.o: $(hdrdir)/ruby/ruby.h +rb_str_dup.o: $(hdrdir)/ruby/st.h +rb_str_dup.o: $(hdrdir)/ruby/subst.h +rb_str_dup.o: rb_str_dup.c set_len.o: $(RUBY_EXTCONF_H) set_len.o: $(arch_hdrdir)/ruby/config.h set_len.o: $(hdrdir)/ruby/backward.h diff --git a/ext/-test-/string/rb_str_dup.c b/ext/-test-/string/rb_str_dup.c new file mode 100644 index 0000000000..a0bd65820f --- /dev/null +++ b/ext/-test-/string/rb_str_dup.c @@ -0,0 +1,35 @@ +#include "ruby.h" + +VALUE rb_str_dup(VALUE str); + +static VALUE +bug_rb_str_dup(VALUE self, VALUE str) +{ + rb_check_type(str, T_STRING); + return rb_str_dup(str); +} + +static VALUE +bug_shared_string_p(VALUE self, VALUE str) +{ + rb_check_type(str, T_STRING); + return RB_FL_TEST(str, RUBY_ELTS_SHARED) && RB_FL_TEST(str, RSTRING_NOEMBED) ? Qtrue : Qfalse; +} + +static VALUE +bug_sharing_with_shared_p(VALUE self, VALUE str) +{ + rb_check_type(str, T_STRING); + if (bug_shared_string_p(self, str)) { + return bug_shared_string_p(self, RSTRING(str)->as.heap.aux.shared); + } + return Qfalse; +} + +void +Init_string_rb_str_dup(VALUE klass) +{ + rb_define_singleton_method(klass, "rb_str_dup", bug_rb_str_dup, 1); + rb_define_singleton_method(klass, "shared_string?", bug_shared_string_p, 1); + rb_define_singleton_method(klass, "sharing_with_shared?", bug_sharing_with_shared_p, 1); +} @@ -1506,10 +1506,13 @@ str_duplicate(VALUE klass, VALUE str) MEMCPY(RSTRING(dup)->as.ary, RSTRING(str)->as.ary, char, embed_size); if (flags & STR_NOEMBED) { - if (UNLIKELY(!(flags & FL_FREEZE))) { - str = str_new_frozen(klass, str); - FL_SET_RAW(str, flags & FL_TAINT); - flags = FL_TEST_RAW(str, flag_mask); + if (FL_TEST_RAW(str, STR_SHARED)) { + str = RSTRING(str)->as.heap.aux.shared; + } + else if (UNLIKELY(!(flags & FL_FREEZE))) { + str = str_new_frozen(klass, str); + FL_SET_RAW(str, flags & FL_TAINT); + flags = FL_TEST_RAW(str, flag_mask); } if (flags & STR_NOEMBED) { RB_OBJ_WRITE(dup, &RSTRING(dup)->as.heap.aux.shared, str); diff --git a/test/-ext-/string/test_rb_str_dup.rb b/test/-ext-/string/test_rb_str_dup.rb new file mode 100644 index 0000000000..49b6af9598 --- /dev/null +++ b/test/-ext-/string/test_rb_str_dup.rb @@ -0,0 +1,16 @@ +require 'test/unit' +require '-test-/string' + +class Test_RbStrDup < Test::Unit::TestCase + def test_nested_shared_non_frozen + str = Bug::String.rb_str_dup(Bug::String.rb_str_dup("a" * 50)) + assert_send([Bug::String, :shared_string?, str]) + assert_not_send([Bug::String, :sharing_with_shared?, str], '[Bug #15792]') + end + + def test_nested_shared_frozen + str = Bug::String.rb_str_dup(Bug::String.rb_str_dup("a" * 50).freeze) + assert_send([Bug::String, :shared_string?, str]) + assert_not_send([Bug::String, :sharing_with_shared?, str], '[Bug #15792]') + end +end diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 1fa5126931..d50380aaf6 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -2972,6 +2972,15 @@ CODE end =end + def test_nesting_shared + a = ('a' * 24).encode(Encoding::ASCII).gsub('x', '') + hash = {} + hash[a] = true + assert_equal(('a' * 24), a) + 4.times { GC.start } + assert_equal(('a' * 24), a, '[Bug #15792]') + end + def test_shared_force_encoding s = "\u{3066}\u{3059}\u{3068}".gsub(//, '') h = {} @@ -1,6 +1,6 @@ #define RUBY_VERSION "2.6.3" #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 81 +#define RUBY_PATCHLEVEL 82 #define RUBY_RELEASE_YEAR 2019 #define RUBY_RELEASE_MONTH 8 |