summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-09-19 11:06:04 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-09-19 11:06:04 +0000
commitac3c851bdeeb85f5e35fe22bc153abd86178a46e (patch)
tree93afaefc0e7b8c44d93756e3e0cb0bd49da3b853
parent3558e886bd3ea1d59a5e84dc0af235ecbc8757e4 (diff)
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
-rw-r--r--ChangeLog6
-rw-r--r--symbol.c52
-rw-r--r--test/ruby/test_symbol.rb8
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 <nobu@ruby-lang.org>
+
+ * 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 <usa@ruby-lang.org>
* 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
@@ -1083,21 +1094,28 @@ rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
}
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