summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--ext/-test-/symbol/type.c34
-rw-r--r--parse.y9
-rw-r--r--test/-ext-/symbol/test_type.rb96
-rw-r--r--test/ruby/test_module.rb6
-rw-r--r--test/ruby/test_object.rb6
-rw-r--r--version.h2
7 files changed, 158 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 1e6144d93f..c41c238e4f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Feb 5 23:39:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (intern_str): sigil only names are junk, at least one
+ identifier character is needed. [ruby-dev:47723] [Bug #8928]
+
+ * parse.y (rb_enc_symname_type): fix out of bound access.
+
Wed Feb 5 22:54:52 2014 Kazuki Tsujimoto <kazuki@callcc.net>
* time.c (get_timeval, get_new_timeval): use rb_obj_class()
diff --git a/ext/-test-/symbol/type.c b/ext/-test-/symbol/type.c
new file mode 100644
index 0000000000..37406d3853
--- /dev/null
+++ b/ext/-test-/symbol/type.c
@@ -0,0 +1,34 @@
+#include "ruby.h"
+
+#ifdef HAVE_RB_IS_CONST_NAME
+# define get_symbol_type(type, t, name) do { \
+ ID id = rb_check_id(&name); \
+ t = (id ? rb_is_##type##_id(id) : rb_is_##type##_name(name)); \
+ } while (0)
+#else
+# define get_symbol_type(type, t, name) do { \
+ t = rb_is_##type##_id(rb_to_id(name)); \
+ } while (0)
+#endif
+
+#define define_symbol_type_p(type) \
+static VALUE \
+bug_sym_##type##_p(VALUE self, VALUE name) \
+{ \
+ int t; \
+ get_symbol_type(type, t, name); \
+ return (t ? Qtrue : Qfalse); \
+}
+
+#define declare_symbol_type_p(type) \
+ rb_define_singleton_method(klass, #type"?", bug_sym_##type##_p, 1);
+
+#define FOREACH_ID_TYPES(x) x(const) x(class) x(global) x(instance) x(attrset) x(local) x(junk)
+
+FOREACH_ID_TYPES(define_symbol_type_p)
+
+void
+Init_type(VALUE klass)
+{
+ FOREACH_ID_TYPES(declare_symbol_type_p)
+}
diff --git a/parse.y b/parse.y
index 9f8b284924..e39a9d01ff 100644
--- a/parse.y
+++ b/parse.y
@@ -10136,6 +10136,7 @@ rb_enc_symname_type(const char *name, long len, rb_encoding *enc)
if (m >= e || (*m != '_' && !rb_enc_isalpha(*m, enc) && ISASCII(*m)))
return -1;
while (m < e && is_identchar(m, e, enc)) m += rb_enc_mbclen(m, e, enc);
+ if (m >= e) break;
switch (*m) {
case '!': case '?':
if (type == ID_GLOBAL || type == ID_CLASS || type == ID_INSTANCE) return -1;
@@ -10243,7 +10244,8 @@ intern_str(VALUE str)
enc = rb_enc_get(str);
symenc = enc;
- if (rb_cString && !rb_enc_asciicompat(enc)) {
+ if (!len || (rb_cString && !rb_enc_asciicompat(enc))) {
+ junk:
id = ID_JUNK;
goto new_id;
}
@@ -10251,6 +10253,7 @@ intern_str(VALUE str)
id = 0;
switch (*m) {
case '$':
+ if (len < 2) goto junk;
id |= ID_GLOBAL;
if ((mb = is_special_global_name(++m, e, enc)) != 0) {
if (!--mb) symenc = rb_usascii_encoding();
@@ -10259,10 +10262,12 @@ intern_str(VALUE str)
break;
case '@':
if (m[1] == '@') {
+ if (len < 3) goto junk;
m++;
id |= ID_CLASS;
}
else {
+ if (len < 2) goto junk;
id |= ID_INSTANCE;
}
m++;
@@ -10288,6 +10293,8 @@ intern_str(VALUE str)
if (m[last] == '=') {
/* attribute assignment */
+ if (!rb_enc_symname2_p(name, last, enc))
+ goto junk;
id = rb_intern3(name, last, enc);
if (id > tLAST_OP_ID && !is_attrset_id(id)) {
enc = rb_enc_get(rb_id2str(id));
diff --git a/test/-ext-/symbol/test_type.rb b/test/-ext-/symbol/test_type.rb
new file mode 100644
index 0000000000..427888eeb9
--- /dev/null
+++ b/test/-ext-/symbol/test_type.rb
@@ -0,0 +1,96 @@
+require 'test/unit'
+require "-test-/symbol"
+
+module Test_Symbol
+ class TestType < Test::Unit::TestCase
+ def assert_symtype(sym, pred, msg = nil)
+ assert_send([Bug::Symbol, pred, sym], msg)
+ end
+
+ def assert_not_symtype(sym, pred, msg = nil)
+ assert_not_send([Bug::Symbol, pred, sym], msg)
+ end
+
+ def test_const
+ assert_symtype("Foo", :const?)
+ assert_not_symtype("F!", :const?)
+ assert_not_symtype("foo", :const?)
+ assert_not_symtype("@foo", :const?)
+ assert_not_symtype("@@foo", :const?)
+ assert_not_symtype("$foo", :const?)
+ assert_not_symtype("foo=", :const?)
+ assert_not_symtype("[foo]", :const?)
+ assert_not_symtype("xFoo", :const?)
+ end
+
+ def test_local
+ assert_symtype("foo", :local?)
+ assert_symtype("fooBar", :local?)
+ assert_symtype("foo_bar", :local?)
+ assert_not_symtype("foo!", :local?)
+ assert_not_symtype("foo?", :local?)
+ assert_not_symtype("Foo", :local?)
+ assert_not_symtype("@foo", :local?)
+ assert_not_symtype("@@foo", :local?)
+ assert_not_symtype("$foo", :local?)
+ assert_not_symtype("foo=", :local?)
+ assert_not_symtype("[foo]", :local?)
+ end
+
+ def test_global
+ assert_symtype("$foo", :global?)
+ assert_symtype("$$", :global?)
+ assert_not_symtype("$()", :global?)
+ assert_not_symtype("$", :global?)
+ assert_not_symtype("foo", :global?)
+ assert_not_symtype("Foo", :global?)
+ assert_not_symtype("@foo", :global?)
+ assert_not_symtype("@@foo", :global?)
+ assert_not_symtype("foo=", :global?)
+ assert_not_symtype("[foo]", :global?)
+ end
+
+ def test_instance
+ assert_symtype("@foo", :instance?)
+ assert_not_symtype("@", :instance?)
+ assert_not_symtype("@1", :instance?)
+ assert_not_symtype("@@", :instance?)
+ assert_not_symtype("foo", :instance?)
+ assert_not_symtype("Foo", :instance?)
+ assert_not_symtype("@@foo", :instance?)
+ assert_not_symtype("$foo", :instance?)
+ assert_not_symtype("foo=", :instance?)
+ assert_not_symtype("[foo]", :instance?)
+ end
+
+ def test_class
+ assert_symtype("@@foo", :class?)
+ assert_not_symtype("@@", :class?)
+ assert_not_symtype("@", :class?)
+ assert_not_symtype("@@1", :class?)
+ assert_not_symtype("foo", :class?)
+ assert_not_symtype("Foo", :class?)
+ assert_not_symtype("@foo", :class?)
+ assert_not_symtype("$foo", :class?)
+ assert_not_symtype("foo=", :class?)
+ assert_not_symtype("[foo]", :class?)
+ end
+
+ def test_attrset
+ assert_symtype("foo=", :attrset?)
+ assert_symtype("Foo=", :attrset?)
+ assert_symtype("@foo=", :attrset?)
+ assert_symtype("@@foo=", :attrset?)
+ assert_symtype("$foo=", :attrset?)
+ assert_not_symtype("0=", :attrset?)
+ assert_not_symtype("@=", :attrset?)
+ assert_not_symtype("@@=", :attrset?)
+ assert_not_symtype("foo", :attrset?)
+ assert_not_symtype("Foo", :attrset?)
+ assert_not_symtype("@foo", :attrset?)
+ assert_not_symtype("@@foo", :attrset?)
+ assert_not_symtype("$foo", :attrset?)
+ assert_not_symtype("[foo]", :attrset?)
+ end
+ end
+end
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index aa2d82841f..91fddabcd0 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -663,6 +663,8 @@ class TestModule < Test::Unit::TestCase
c.class_eval('@@foo = :foo')
assert_equal(:foo, c.class_variable_get(:@@foo))
assert_raise(NameError) { c.class_variable_get(:@@bar) } # c.f. instance_variable_get
+ assert_raise(NameError) { c.class_variable_get(:'@@') }
+ assert_raise(NameError) { c.class_variable_get('@@') }
assert_raise(NameError) { c.class_variable_get(:foo) }
end
@@ -670,6 +672,8 @@ class TestModule < Test::Unit::TestCase
c = Class.new
c.class_variable_set(:@@foo, :foo)
assert_equal(:foo, c.class_eval('@@foo'))
+ assert_raise(NameError) { c.class_variable_set(:'@@', 1) }
+ assert_raise(NameError) { c.class_variable_set('@@', 1) }
assert_raise(NameError) { c.class_variable_set(:foo, 1) }
end
@@ -678,6 +682,8 @@ class TestModule < Test::Unit::TestCase
c.class_eval('@@foo = :foo')
assert_equal(true, c.class_variable_defined?(:@@foo))
assert_equal(false, c.class_variable_defined?(:@@bar))
+ assert_raise(NameError) { c.class_variable_defined?(:'@@') }
+ assert_raise(NameError) { c.class_variable_defined?('@@') }
assert_raise(NameError) { c.class_variable_defined?(:foo) }
end
diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb
index 9936ecda5a..3bb07dd1b0 100644
--- a/test/ruby/test_object.rb
+++ b/test/ruby/test_object.rb
@@ -164,6 +164,8 @@ class TestObject < Test::Unit::TestCase
o.instance_eval { @foo = :foo }
assert_equal(:foo, o.instance_variable_get(:@foo))
assert_equal(nil, o.instance_variable_get(:@bar))
+ assert_raise(NameError) { o.instance_variable_get('@') }
+ assert_raise(NameError) { o.instance_variable_get(:'@') }
assert_raise(NameError) { o.instance_variable_get(:foo) }
end
@@ -171,6 +173,8 @@ class TestObject < Test::Unit::TestCase
o = Object.new
o.instance_variable_set(:@foo, :foo)
assert_equal(:foo, o.instance_eval { @foo })
+ assert_raise(NameError) { o.instance_variable_set(:'@', 1) }
+ assert_raise(NameError) { o.instance_variable_set('@', 1) }
assert_raise(NameError) { o.instance_variable_set(:foo, 1) }
end
@@ -179,6 +183,8 @@ class TestObject < Test::Unit::TestCase
o.instance_eval { @foo = :foo }
assert_equal(true, o.instance_variable_defined?(:@foo))
assert_equal(false, o.instance_variable_defined?(:@bar))
+ assert_raise(NameError) { o.instance_variable_defined?(:'@') }
+ assert_raise(NameError) { o.instance_variable_defined?('@') }
assert_raise(NameError) { o.instance_variable_defined?(:foo) }
end
diff --git a/version.h b/version.h
index 5f32612721..9f2913e061 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.0.0"
#define RUBY_RELEASE_DATE "2014-02-05"
-#define RUBY_PATCHLEVEL 395
+#define RUBY_PATCHLEVEL 396
#define RUBY_RELEASE_YEAR 2014
#define RUBY_RELEASE_MONTH 2