* object.c (rb_mod_{const,cvar}_defined, rb_obj_ivar_defined):
avoid inadvertent symbol creation in reflection methods. based on a patch by Jeremy Evans at [ruby-core:38367]. [Feature #5072] * vm_method.c (rb_mod_method_defined) (rb_mod_{public,private,protected}_method_defined) (obj_respond_to): ditto. * parse.y (rb_check_id): new function returns already interned ID or 0. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32621 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
c276b73804
commit
34918aa832
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
Fri Jul 22 21:06:39 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* object.c (rb_mod_{const,cvar}_defined, rb_obj_ivar_defined):
|
||||
avoid inadvertent symbol creation in reflection methods. based
|
||||
on a patch by Jeremy Evans at [ruby-core:38367]. [Feature #5072]
|
||||
|
||||
* vm_method.c (rb_mod_method_defined)
|
||||
(rb_mod_{public,private,protected}_method_defined)
|
||||
(obj_respond_to): ditto.
|
||||
|
||||
* parse.y (rb_check_id): new function returns already interned ID
|
||||
or 0.
|
||||
|
||||
Fri Jul 22 20:44:49 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* parse.y (rb_is_global_id, rb_is_attrset_id): add missing
|
||||
|
@ -1098,6 +1098,7 @@ ID rb_intern(const char*);
|
||||
ID rb_intern2(const char*, long);
|
||||
ID rb_intern_str(VALUE str);
|
||||
const char *rb_id2name(ID);
|
||||
ID rb_check_id(VALUE);
|
||||
ID rb_to_id(VALUE);
|
||||
VALUE rb_id2str(ID);
|
||||
|
||||
|
@ -133,6 +133,14 @@ VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
|
||||
/* parse.y */
|
||||
VALUE rb_parser_get_yydebug(VALUE);
|
||||
VALUE rb_parser_set_yydebug(VALUE, VALUE);
|
||||
int rb_is_const_name(VALUE name);
|
||||
int rb_is_class_name(VALUE name);
|
||||
int rb_is_global_name(VALUE name);
|
||||
int rb_is_instance_name(VALUE name);
|
||||
int rb_is_attrset_name(VALUE name);
|
||||
int rb_is_local_name(VALUE name);
|
||||
int rb_is_method_name(VALUE name);
|
||||
int rb_is_junk_name(VALUE name);
|
||||
|
||||
/* proc.c */
|
||||
VALUE rb_proc_location(VALUE self);
|
||||
|
9
object.c
9
object.c
@ -1833,7 +1833,8 @@ rb_mod_const_defined(int argc, VALUE *argv, VALUE mod)
|
||||
else {
|
||||
rb_scan_args(argc, argv, "11", &name, &recur);
|
||||
}
|
||||
id = rb_to_id(name);
|
||||
if (!(id = rb_check_id(name)) && rb_is_const_name(name))
|
||||
return Qfalse;
|
||||
if (!rb_is_const_id(id)) {
|
||||
rb_name_error(id, "wrong constant name %s", rb_id2name(id));
|
||||
}
|
||||
@ -1923,8 +1924,9 @@ rb_obj_ivar_set(VALUE obj, VALUE iv, VALUE val)
|
||||
static VALUE
|
||||
rb_obj_ivar_defined(VALUE obj, VALUE iv)
|
||||
{
|
||||
ID id = rb_to_id(iv);
|
||||
ID id = rb_check_id(iv);
|
||||
|
||||
if (!id && rb_is_instance_name(iv)) return Qfalse;
|
||||
if (!rb_is_instance_id(id)) {
|
||||
rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id));
|
||||
}
|
||||
@ -2002,8 +2004,9 @@ rb_mod_cvar_set(VALUE obj, VALUE iv, VALUE val)
|
||||
static VALUE
|
||||
rb_mod_cvar_defined(VALUE obj, VALUE iv)
|
||||
{
|
||||
ID id = rb_to_id(iv);
|
||||
ID id = rb_check_id(iv);
|
||||
|
||||
if (!id && rb_is_class_name(iv)) return Qfalse;
|
||||
if (!rb_is_class_id(id)) {
|
||||
rb_name_error(id, "`%s' is not allowed as a class variable name", rb_id2name(id));
|
||||
}
|
||||
|
137
parse.y
137
parse.y
@ -9678,24 +9678,29 @@ rb_enc_symname_p(const char *name, rb_encoding *enc)
|
||||
return rb_enc_symname2_p(name, strlen(name), enc);
|
||||
}
|
||||
|
||||
int
|
||||
rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
|
||||
static int
|
||||
rb_enc_symname_type(const char *name, long len, rb_encoding *enc)
|
||||
{
|
||||
const char *m = name;
|
||||
const char *e = m + len;
|
||||
int localid = FALSE;
|
||||
int type = ID_JUNK;
|
||||
|
||||
if (!m || len <= 0) return FALSE;
|
||||
if (!m || len <= 0) return -1;
|
||||
switch (*m) {
|
||||
case '\0':
|
||||
return FALSE;
|
||||
return -1;
|
||||
|
||||
case '$':
|
||||
if (is_special_global_name(++m, e, enc)) return TRUE;
|
||||
type = ID_GLOBAL;
|
||||
if (is_special_global_name(++m, e, enc)) return type;
|
||||
goto id;
|
||||
|
||||
case '@':
|
||||
if (*++m == '@') ++m;
|
||||
type = ID_INSTANCE;
|
||||
if (*++m == '@') {
|
||||
++m;
|
||||
type = ID_CLASS;
|
||||
}
|
||||
goto id;
|
||||
|
||||
case '<':
|
||||
@ -9716,7 +9721,7 @@ rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
|
||||
switch (*++m) {
|
||||
case '~': ++m; break;
|
||||
case '=': if (*++m == '=') ++m; break;
|
||||
default: return FALSE;
|
||||
default: return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -9733,32 +9738,53 @@ rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
|
||||
break;
|
||||
|
||||
case '[':
|
||||
if (*++m != ']') return FALSE;
|
||||
if (*++m != ']') return -1;
|
||||
if (*++m == '=') ++m;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
if (len == 1) return FALSE;
|
||||
if (len == 1) return ID_JUNK;
|
||||
switch (*++m) {
|
||||
case '=': case '~': ++m; break;
|
||||
default: return FALSE;
|
||||
default: return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
localid = !rb_enc_isupper(*m, enc);
|
||||
type = rb_enc_isupper(*m, enc) ? ID_CONST : ID_LOCAL;
|
||||
id:
|
||||
if (m >= e || (*m != '_' && !rb_enc_isalpha(*m, enc) && ISASCII(*m)))
|
||||
return FALSE;
|
||||
return -1;
|
||||
while (m < e && is_identchar(m, e, enc)) m += rb_enc_mbclen(m, e, enc);
|
||||
if (localid) {
|
||||
switch (*m) {
|
||||
case '!': case '?': case '=': ++m;
|
||||
}
|
||||
switch (*m) {
|
||||
case '!': case '?':
|
||||
type = ID_JUNK;
|
||||
++m;
|
||||
break;
|
||||
case '=':
|
||||
type = ID_ATTRSET;
|
||||
++m;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return m == e;
|
||||
return m == e ? type : -1;
|
||||
}
|
||||
|
||||
int
|
||||
rb_enc_symname2_p(const char *name, long len, rb_encoding *enc)
|
||||
{
|
||||
return rb_enc_symname_type(name, len, enc) != -1;
|
||||
}
|
||||
|
||||
static int
|
||||
rb_str_symname_type(VALUE name)
|
||||
{
|
||||
const char *ptr = StringValuePtr(name);
|
||||
long len = RSTRING_LEN(name);
|
||||
int type = rb_enc_symname_type(ptr, len, rb_enc_get(name));
|
||||
RB_GC_GUARD(name);
|
||||
return type;
|
||||
}
|
||||
|
||||
static ID
|
||||
@ -10076,6 +10102,81 @@ rb_is_junk_id(ID id)
|
||||
return is_junk_id(id);
|
||||
}
|
||||
|
||||
ID
|
||||
rb_check_id(VALUE name)
|
||||
{
|
||||
st_data_t id;
|
||||
VALUE tmp;
|
||||
|
||||
if (SYMBOL_P(name)) {
|
||||
return SYM2ID(name);
|
||||
}
|
||||
else if (RB_TYPE_P(name, T_STRING)) {
|
||||
tmp = rb_check_string_type(name);
|
||||
if (NIL_P(tmp)) {
|
||||
tmp = rb_inspect(name);
|
||||
rb_raise(rb_eTypeError, "%s is not a symbol",
|
||||
RSTRING_PTR(tmp));
|
||||
}
|
||||
name = tmp;
|
||||
}
|
||||
if (!st_lookup(global_symbols.sym_id, (st_data_t)name, &id))
|
||||
return (ID)0;
|
||||
return (ID)id;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_const_name(VALUE name)
|
||||
{
|
||||
return rb_str_symname_type(name) == ID_CONST;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_class_name(VALUE name)
|
||||
{
|
||||
return rb_str_symname_type(name) == ID_CLASS;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_global_name(VALUE name)
|
||||
{
|
||||
return rb_str_symname_type(name) == ID_GLOBAL;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_instance_name(VALUE name)
|
||||
{
|
||||
return rb_str_symname_type(name) == ID_INSTANCE;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_attrset_name(VALUE name)
|
||||
{
|
||||
return rb_str_symname_type(name) == ID_ATTRSET;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_local_name(VALUE name)
|
||||
{
|
||||
return rb_str_symname_type(name) == ID_LOCAL;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_method_name(VALUE name)
|
||||
{
|
||||
switch (rb_str_symname_type(name)) {
|
||||
case ID_LOCAL: case ID_ATTRSET: case ID_JUNK:
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
rb_is_junk_name(VALUE name)
|
||||
{
|
||||
return rb_str_symname_type(name) == -1;
|
||||
}
|
||||
|
||||
#endif /* !RIPPER */
|
||||
|
||||
static void
|
||||
|
@ -495,6 +495,9 @@ class TestModule < Test::Unit::TestCase
|
||||
def test_const_get_invalid_name
|
||||
c1 = Class.new
|
||||
assert_raise(NameError) { c1.const_defined?(:foo) }
|
||||
name = "gadzooks"
|
||||
assert !Symbol.all_symbols.any? {|sym| sym.to_s == name}
|
||||
assert_raise(NameError) { c1.const_defined?(name) }
|
||||
end
|
||||
|
||||
def test_const_get_no_inherited
|
||||
|
@ -144,4 +144,19 @@ class TestSymbol < Test::Unit::TestCase
|
||||
assert_equal(':"\\u3042\\u3044\\u3046"', "\u3042\u3044\u3046".encode(e).to_sym.inspect)
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_inadvertent_symbol_creation
|
||||
feature5072 = '[ruby-core:38367]'
|
||||
c = Class.new
|
||||
s = "gadzooks"
|
||||
{:respond_to? => "#{s}1", :method_defined? => "#{s}2",
|
||||
:public_method_defined? => "#{s}3", :private_method_defined? => "#{s}4",
|
||||
:protected_method_defined? => "#{s}5", :const_defined? => "A#{s}",
|
||||
:instance_variable_defined? => "@#{s}", :class_variable_defined? => "@@#{s}"
|
||||
}.each do |meth, str|
|
||||
msg = "#{meth}(#{str}) #{feature5072}"
|
||||
assert !c.send(meth, str), msg
|
||||
assert !Symbol.all_symbols.any? {|sym| sym.to_s == str}, msg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
18
vm_method.c
18
vm_method.c
@ -713,7 +713,8 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
|
||||
static VALUE
|
||||
rb_mod_method_defined(VALUE mod, VALUE mid)
|
||||
{
|
||||
if (!rb_method_boundp(mod, rb_to_id(mid), 1)) {
|
||||
ID id = rb_check_id(mid);
|
||||
if (!id || !rb_method_boundp(mod, id, 1)) {
|
||||
return Qfalse;
|
||||
}
|
||||
return Qtrue;
|
||||
@ -763,7 +764,9 @@ check_definition(VALUE mod, ID mid, rb_method_flag_t noex)
|
||||
static VALUE
|
||||
rb_mod_public_method_defined(VALUE mod, VALUE mid)
|
||||
{
|
||||
return check_definition(mod, rb_to_id(mid), NOEX_PUBLIC);
|
||||
ID id = rb_check_id(mid);
|
||||
if (!id) return Qfalse;
|
||||
return check_definition(mod, id, NOEX_PUBLIC);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -795,7 +798,9 @@ rb_mod_public_method_defined(VALUE mod, VALUE mid)
|
||||
static VALUE
|
||||
rb_mod_private_method_defined(VALUE mod, VALUE mid)
|
||||
{
|
||||
return check_definition(mod, rb_to_id(mid), NOEX_PRIVATE);
|
||||
ID id = rb_check_id(mid);
|
||||
if (!id) return Qfalse;
|
||||
return check_definition(mod, id, NOEX_PRIVATE);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -827,7 +832,9 @@ rb_mod_private_method_defined(VALUE mod, VALUE mid)
|
||||
static VALUE
|
||||
rb_mod_protected_method_defined(VALUE mod, VALUE mid)
|
||||
{
|
||||
return check_definition(mod, rb_to_id(mid), NOEX_PROTECTED);
|
||||
ID id = rb_check_id(mid);
|
||||
if (!id) return Qfalse;
|
||||
return check_definition(mod, id, NOEX_PROTECTED);
|
||||
}
|
||||
|
||||
int
|
||||
@ -1238,7 +1245,8 @@ obj_respond_to(int argc, VALUE *argv, VALUE obj)
|
||||
ID id;
|
||||
|
||||
rb_scan_args(argc, argv, "11", &mid, &priv);
|
||||
id = rb_to_id(mid);
|
||||
if (!(id = rb_check_id(mid)))
|
||||
return Qfalse;
|
||||
if (basic_obj_respond_to(obj, id, !RTEST(priv)))
|
||||
return Qtrue;
|
||||
return Qfalse;
|
||||
|
Loading…
x
Reference in New Issue
Block a user