summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--proc.c9
-rw-r--r--test/ruby/test_method.rb23
-rw-r--r--vm.c9
4 files changed, 50 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index fae1813e04..0349f7c13a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Wed Dec 25 16:58:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (rb_mod_define_method): consider visibility only if self
+ in the caller is same as the receiver, otherwise make public as
+ well as old behavior. [ruby-core:57747] [Bug #9005]
+ [ruby-core:58497] [Bug #9141]
+
+ * vm.c (rb_vm_cref_in_context): return ruby level cref if self is
+ same.
+
Wed Dec 25 16:35:34 2013 Yusuke Endoh <mame@tsg.ne.jp>
* sample/trick2013/: added the award-winning entries of TRICK 2013.
diff --git a/proc.c b/proc.c
index 638f22cb80..f8b2e3b3a9 100644
--- a/proc.c
+++ b/proc.c
@@ -14,6 +14,8 @@
#include "gc.h"
#include "iseq.h"
+NODE *rb_vm_cref_in_context(VALUE self);
+
struct METHOD {
VALUE recv;
VALUE rclass;
@@ -1619,7 +1621,12 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
{
ID id;
VALUE body;
- int noex = (int)rb_vm_cref()->nd_visi;
+ int noex = NOEX_PUBLIC;
+ const NODE *cref = rb_vm_cref_in_context(mod);
+
+ if (cref && cref->nd_clss == mod) {
+ noex = (int)cref->nd_visi;
+ }
if (argc == 1) {
id = rb_to_id(argv[0]);
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index 2fde505183..5b7c76da4d 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -338,6 +338,29 @@ class TestMethod < Test::Unit::TestCase
assert_equal(true, m.private_method_defined?(:foo))
end
+ def test_define_method_in_private_scope
+ bug9005 = '[ruby-core:57747] [Bug #9005]'
+ c = Class.new
+ class << c
+ public :define_method
+ end
+ TOPLEVEL_BINDING.eval("proc{|c|c.define_method(:x) {|*x|throw x}}").call(c)
+ o = c.new
+ assert_throw(bug9005) {o.x(bug9005)}
+ end
+
+ def test_singleton_define_method_in_private_scope
+ bug9141 = '[ruby-core:58497] [Bug #9141]'
+ o = Object.new
+ class << o
+ public :define_singleton_method
+ end
+ TOPLEVEL_BINDING.eval("proc{|o|o.define_singleton_method(:x) {|x|throw x}}").call(o)
+ assert_throw(bug9141) do
+ o.x(bug9141)
+ end
+ end
+
def test_super_in_proc_from_define_method
c1 = Class.new {
def m
diff --git a/vm.c b/vm.c
index e1c629867b..947b1811e5 100644
--- a/vm.c
+++ b/vm.c
@@ -930,6 +930,15 @@ rb_vm_cref(void)
return rb_vm_get_cref(cfp->iseq, cfp->ep);
}
+NODE *
+rb_vm_cref_in_context(VALUE self)
+{
+ rb_thread_t *th = GET_THREAD();
+ const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
+ if (cfp->self != self) return NULL;
+ return rb_vm_get_cref(cfp->iseq, cfp->ep);
+}
+
#if 0
void
debug_cref(NODE *cref)