From 499cd410c0c1a3e898ad820c69fa6b537d4b4604 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Thu, 21 Jul 2011 14:46:16 -0700 Subject: [PATCH 1/2] Add String#interned? for checking if a string is already a present symbol This can be used to check user input to make sure that you don't allow arbitrary symbol creation, which can lead to denial of service through memory exhaustion. This implementation is similar to the rb_sym_interned_p function added in r10932 (and apparently removed later, though left in include/ruby/intern.h). --- include/ruby/intern.h | 2 +- parse.y | 9 +++++++++ string.c | 1 + test/ruby/test_parse.rb | 9 +++++++++ 4 files changed, 20 insertions(+), 1 deletions(-) diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 5719a0d..d88293d 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -561,7 +561,7 @@ int rb_is_class_id(ID); int rb_is_local_id(ID); int rb_is_junk_id(ID); int rb_symname_p(const char*); -int rb_sym_interned_p(VALUE); +VALUE rb_str_interned_p(VALUE); void rb_gc_mark_symbols(void); VALUE rb_backref_get(void); void rb_backref_set(VALUE); diff --git a/parse.y b/parse.y index aca2b6a..db8791b 100644 --- a/parse.y +++ b/parse.y @@ -10034,6 +10034,15 @@ rb_sym_all_symbols(void) return ary; } +VALUE +rb_str_interned_p(VALUE str) +{ + st_data_t data; + if (st_lookup(global_symbols.sym_id, (st_data_t)str, &data)) + return Qtrue; + return Qfalse; +} + int rb_is_const_id(ID id) { diff --git a/string.c b/string.c index 711918b..7dbd933 100644 --- a/string.c +++ b/string.c @@ -7847,6 +7847,7 @@ Init_String(void) rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1); rb_define_method(rb_cString, "valid_encoding?", rb_str_valid_encoding_p, 0); rb_define_method(rb_cString, "ascii_only?", rb_str_is_ascii_only_p, 0); + rb_define_method(rb_cString, "interned?", rb_str_interned_p, 0); /* in parse.y */ id_to_s = rb_intern("to_s"); diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index 14990be..99a6edf 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -819,6 +819,15 @@ x = __ENCODING__ assert(x.all? {|s| s.is_a?(Symbol) }) end + def test_string_interned + str = "test_string_interned" + assert str.interned? + assert Symbol.all_symbols.any?{|sym| sym.to_s == str} + str = "gadzooks!123" + assert !str.interned? + assert !Symbol.all_symbols.any?{|sym| sym.to_s == str} + end + def test_is_class_id c = Class.new assert_raise(NameError) do -- 1.7.5