ruby-changes:39280
From: nobu <ko1@a...>
Date: Fri, 24 Jul 2015 16:39:09 +0900 (JST)
Subject: [ruby-changes:39280] nobu:r51360 (trunk): string.c: pool only bare strings in fstring
nobu 2015-07-24 16:38:37 +0900 (Fri, 24 Jul 2015) New Revision: 51360 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51360 Log: string.c: pool only bare strings in fstring * string.c (fstr_update_callback): pool bare strings only. * string.c (rb_fstring): return the original string with sharing a fstring if it has extra attributes, not the fstring itself. [ruby-dev:49188] [Bug #11386] Added files: trunk/ext/-test-/string/fstring.c trunk/test/-ext-/string/test_fstring.rb Modified files: trunk/ChangeLog trunk/string.c Index: ChangeLog =================================================================== --- ChangeLog (revision 51359) +++ ChangeLog (revision 51360) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Jul 24 16:35:55 2015 Nobuyoshi Nakada <nobu@r...> + + * string.c (fstr_update_callback): pool bare strings only. + + * string.c (rb_fstring): return the original string with sharing a + fstring if it has extra attributes, not the fstring itself. + [ruby-dev:49188] [Bug #11386] + Fri Jul 24 16:35:34 2015 yui-knk <spiketeika@g...> * file.c (rb_file_s_extname): [DOC] add an example. Index: string.c =================================================================== --- string.c (revision 51359) +++ string.c (revision 51360) @@ -155,6 +155,9 @@ VALUE rb_cSymbol; https://github.com/ruby/ruby/blob/trunk/string.c#L155 #define SHARABLE_SUBSTRING_P(beg, len, end) 1 #endif +static VALUE str_replace_shared_without_enc(VALUE str2, VALUE str); +static VALUE str_new_shared(VALUE klass, VALUE str); +static VALUE str_new_frozen(VALUE klass, VALUE orig); static VALUE str_new_static(VALUE klass, const char *ptr, long len, int encindex); static void str_make_independent_expand(VALUE str, long expand); @@ -228,6 +231,8 @@ static const struct st_hash_type fstring https://github.com/ruby/ruby/blob/trunk/string.c#L231 rb_str_hash, }; +#define BARE_STRING_P(str) (!FL_ANY_RAW(str, FL_TAINT|FL_EXIVAR) && RBASIC_CLASS(str) == rb_cString) + static int fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing) { @@ -254,10 +259,15 @@ fstr_update_callback(st_data_t *key, st_ https://github.com/ruby/ruby/blob/trunk/string.c#L259 OBJ_FREEZE_RAW(str); } else { - str = rb_str_new_frozen(str); + str = str_new_frozen(rb_cString, str); if (STR_SHARED_P(str)) { /* str should not be shared */ /* shared substring */ str_make_independent_expand(str, 0L); + assert(OBJ_FROZEN(str)); + } + if (!BARE_STRING_P(str)) { + str = str_new_shared(rb_cString, str); + OBJ_FREEZE_RAW(str); } } RBASIC(str)->flags |= RSTRING_FSTR; @@ -267,15 +277,32 @@ fstr_update_callback(st_data_t *key, st_ https://github.com/ruby/ruby/blob/trunk/string.c#L277 } } +RUBY_FUNC_EXPORTED VALUE rb_fstring(VALUE str) { + VALUE fstr; + int bare; + Check_Type(str, T_STRING); if (FL_TEST(str, RSTRING_FSTR)) return str; - return register_fstring(str); + bare = BARE_STRING_P(str); + if (STR_EMBED_P(str) && !bare) { + OBJ_FREEZE_RAW(str); + return str; + } + + fstr = register_fstring(str); + + if (!bare) { + str_replace_shared_without_enc(str, fstr); + OBJ_FREEZE_RAW(str); + return str; + } + return fstr; } static VALUE @@ -286,11 +313,14 @@ register_fstring(VALUE str) https://github.com/ruby/ruby/blob/trunk/string.c#L313 do { ret = str; st_update(rb_vm_fstring_table(), (st_data_t)str, - fstr_update_callback, (st_data_t)&ret); + fstr_update_callback, (st_data_t)&ret); } while (ret == Qundef); assert(OBJ_FROZEN(ret)); assert(!FL_TEST_RAW(ret, STR_FAKESTR)); + assert(!FL_TEST_RAW(ret, FL_EXIVAR)); + assert(!FL_TEST_RAW(ret, FL_TAINT)); + assert(RBASIC_CLASS(ret) == rb_cString); return ret; } @@ -972,11 +1002,15 @@ rb_str_new_shared(VALUE str) https://github.com/ruby/ruby/blob/trunk/string.c#L1002 VALUE rb_str_new_frozen(VALUE orig) { - VALUE klass, str; - if (OBJ_FROZEN(orig)) return orig; - klass = rb_obj_class(orig); + return str_new_frozen(rb_obj_class(orig), orig); +} + +static VALUE +str_new_frozen(VALUE klass, VALUE orig) +{ + VALUE str; if (STR_EMBED_P(orig)) { str = str_new(klass, RSTRING_PTR(orig), RSTRING_LEN(orig)); Index: ext/-test-/string/fstring.c =================================================================== --- ext/-test-/string/fstring.c (revision 0) +++ ext/-test-/string/fstring.c (revision 51360) @@ -0,0 +1,15 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/string/fstring.c#L1 +#include "ruby.h" + +VALUE rb_fstring(VALUE str); + +VALUE +bug_s_fstring(VALUE self, VALUE str) +{ + return rb_fstring(str); +} + +void +Init_fstring(VALUE klass) +{ + rb_define_singleton_method(klass, "fstring", bug_s_fstring, 1); +} Property changes on: ext/-test-/string/fstring.c ___________________________________________________________________ Added: svn:eol-style + LF Index: test/-ext-/string/test_fstring.rb =================================================================== --- test/-ext-/string/test_fstring.rb (revision 0) +++ test/-ext-/string/test_fstring.rb (revision 51360) @@ -0,0 +1,64 @@ https://github.com/ruby/ruby/blob/trunk/test/-ext-/string/test_fstring.rb#L1 +require 'test/unit' +require '-test-/string' + +class Test_String_Fstring < Test::Unit::TestCase + def assert_fstring(str) + fstr = Bug::String.fstring(str) + yield str + yield fstr + end + + def test_taint_shared_string + str = __method__.to_s.dup + str.taint + assert_fstring(str) {|s| assert_predicate(s, :tainted?)} + end + + def test_taint_normal_string + str = __method__.to_s * 3 + str.taint + assert_fstring(str) {|s| assert_predicate(s, :tainted?)} + end + + def test_taint_registered_tainted + str = __method__.to_s * 3 + str.taint + assert_fstring(str) {|s| assert_predicate(s, :tainted?)} + + str = __method__.to_s * 3 + assert_fstring(str) {|s| assert_not_predicate(s, :tainted?)} + end + + def test_taint_registered_untainted + str = __method__.to_s * 3 + assert_fstring(str) {|s| assert_not_predicate(s, :tainted?)} + + str = __method__.to_s * 3 + str.taint + assert_fstring(str) {|s| assert_predicate(s, :tainted?)} + end + + def test_instance_variable + str = __method__.to_s * 3 + str.instance_variable_set(:@test, 42) + str.freeze + assert_fstring(str) {|s| assert_send([s, :instance_variable_defined?, :@test])} + end + + def test_singleton_method + str = __method__.to_s * 3 + def str.foo + end + str.freeze + assert_fstring(str) {|s| assert_send([s, :respond_to?, :foo])} + end + + class S < String + end + + def test_subclass + str = S.new(__method__.to_s * 3) + str.freeze + assert_fstring(str) {|s| assert_instance_of(S, s)} + end +end Property changes on: test/-ext-/string/test_fstring.rb ___________________________________________________________________ Added: svn:eol-style + LF -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/