From ac3c851bdeeb85f5e35fe22bc153abd86178a46e Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 19 Sep 2014 11:06:04 +0000 Subject: [PATCH] symbol.c: fix dynamic attrset ID * symbol.c (rb_str_dynamic_intern): check if the stem ID of attrset ID is already registered as a static ID. [ruby-dev:48559] [Bug #10259] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47643 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 +++++ symbol.c | 52 +++++++++++++++++++++++++++------------- test/ruby/test_symbol.rb | 8 +++++++ 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index a44ab3126a..a89b9c9f05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Fri Sep 19 20:06:00 2014 Nobuyoshi Nakada + + * symbol.c (rb_str_dynamic_intern): check if the stem ID of + attrset ID is already registered as a static ID. + [ruby-dev:48559] [Bug #10259] + Fri Sep 19 15:48:09 2014 NAKAMURA Usaku * win32/win32.c (VCSUP): nothing to do if this worktree is not under diff --git a/symbol.c b/symbol.c index 9cb2fe478e..6a1c0d351a 100644 --- a/symbol.c +++ b/symbol.c @@ -103,13 +103,14 @@ Init_sym(void) Init_id(); } -WARN_UNUSED_RESULT(static VALUE dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding *const enc)); +WARN_UNUSED_RESULT(static VALUE dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding *const enc, const ID type)); WARN_UNUSED_RESULT(static VALUE dsymbol_check(const VALUE sym)); WARN_UNUSED_RESULT(static ID dsymbol_pindown(VALUE sym)); WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str)); WARN_UNUSED_RESULT(static VALUE lookup_str_sym(const VALUE str)); WARN_UNUSED_RESULT(static VALUE lookup_id_str(ID id)); WARN_UNUSED_RESULT(static ID attrsetname_to_attr(VALUE name)); +WARN_UNUSED_RESULT(static ID attrsetname_to_attr_id(VALUE name)); ID rb_id_attrset(ID id) @@ -416,10 +417,9 @@ must_be_dynamic_symbol(VALUE x) } static VALUE -dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding * const enc) +dsymbol_alloc(const VALUE klass, const VALUE str, rb_encoding * const enc, const ID type) { const VALUE dsym = rb_newobj_of(klass, T_SYMBOL | FL_WB_PROTECTED); - const ID type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN); rb_enc_associate(dsym, enc); OBJ_FREEZE(dsym); @@ -441,10 +441,11 @@ dsymbol_check(const VALUE sym) { if (UNLIKELY(rb_objspace_garbage_object_p(sym))) { const VALUE fstr = RSYMBOL(sym)->fstr; + const ID type = RSYMBOL(sym)->type; RSYMBOL(sym)->fstr = 0; unregister_sym(fstr, sym); - return dsymbol_alloc(rb_cSymbol, fstr, rb_enc_get(fstr)); + return dsymbol_alloc(rb_cSymbol, fstr, rb_enc_get(fstr), type); } else { return sym; @@ -737,6 +738,7 @@ rb_str_dynamic_intern(VALUE str) #if USE_SYMBOL_GC rb_encoding *enc, *ascii; VALUE sym = lookup_str_sym(str); + ID type; if (sym) { return sym; @@ -753,7 +755,16 @@ rb_str_dynamic_intern(VALUE str) } } - return dsymbol_alloc(rb_cSymbol, rb_fstring(str), enc); + type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN); + if (type == ID_ATTRSET) { + ID attr_id = attrsetname_to_attr_id(str); + if (attr_id && !ID_DYNAMIC_SYM_P(attr_id)) { + attr_id = rb_id_attrset(attr_id); + return ID2SYM(attr_id); + } + } + + return dsymbol_alloc(rb_cSymbol, rb_fstring(str), enc, type); #else return rb_str_intern(str); #endif @@ -1082,22 +1093,29 @@ rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc) return Qnil; } +static ID +attrsetname_to_attr_id(VALUE name) +{ + ID id; + struct RString fake_str; + /* make local name by chopping '=' */ + const VALUE localname = rb_setup_fake_str(&fake_str, + RSTRING_PTR(name), RSTRING_LEN(name) - 1, + rb_enc_get(name)); + OBJ_FREEZE(localname); + + if ((id = lookup_str_id(localname)) != 0) { + return id; + } + RB_GC_GUARD(name); + return (ID)0; +} + static ID attrsetname_to_attr(VALUE name) { if (rb_is_attrset_name(name)) { - ID id; - struct RString fake_str; - /* make local name by chopping '=' */ - const VALUE localname = rb_setup_fake_str(&fake_str, - RSTRING_PTR(name), RSTRING_LEN(name) - 1, - rb_enc_get(name)); - OBJ_FREEZE(localname); - - if ((id = lookup_str_id(localname)) != 0) { - return id; - } - RB_GC_GUARD(name); + return attrsetname_to_attr_id(name); } return (ID)0; diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb index 30ed26272f..a25e6fb5d2 100644 --- a/test/ruby/test_symbol.rb +++ b/test/ruby/test_symbol.rb @@ -222,4 +222,12 @@ class TestSymbol < Test::Unit::TestCase '', child_env: '--disable-gems') end + + def test_dynamic_attrset_id + bug10259 = '[ruby-dev:48559] [Bug #10259]' + class << (obj = Object.new) + attr_writer :unagi + end + assert_nothing_raised(NoMethodError, bug10259) {obj.send("unagi=".intern, 1)} + end end