summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2020-06-03 23:06:06 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2020-06-04 02:12:57 +0900
commit184f78314e98cab63e7503cead4a4e99bd132a08 (patch)
tree97ba75dd05fc557a30ec400627980b9385f66ab2
parent8340c773e54feb399c9fab322e3ff6dd578ac04d (diff)
Properly resolve refinements in defined? on private call [Bug #16932]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3180
-rw-r--r--internal/vm.h6
-rw-r--r--test/ruby/test_defined.rb21
-rw-r--r--vm_insnhelper.c5
-rw-r--r--vm_method.c6
4 files changed, 34 insertions, 4 deletions
diff --git a/internal/vm.h b/internal/vm.h
index 152f13601a..657202ba7f 100644
--- a/internal/vm.h
+++ b/internal/vm.h
@@ -95,6 +95,12 @@ MJIT_SYMBOL_EXPORT_BEGIN
void rb_vm_search_method_slowpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass);
MJIT_SYMBOL_EXPORT_END
+/* vm_method.c */
+struct rb_execution_context_struct;
+MJIT_SYMBOL_EXPORT_BEGIN
+int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv);
+MJIT_SYMBOL_EXPORT_END
+
/* vm_dump.c */
void rb_print_backtrace(void);
diff --git a/test/ruby/test_defined.rb b/test/ruby/test_defined.rb
index 6ad4854b98..b22db700da 100644
--- a/test/ruby/test_defined.rb
+++ b/test/ruby/test_defined.rb
@@ -309,24 +309,45 @@ class TestDefined < Test::Unit::TestCase
refine RefinedClass do
def pub
end
+
+ private
+
+ def priv
+ end
end
def self.call_without_using(x = RefinedClass.new)
defined?(x.pub)
end
+ def self.vcall_without_using(x = RefinedClass.new)
+ x.instance_eval {defined?(priv)}
+ end
+
using self
def self.call_with_using(x = RefinedClass.new)
defined?(x.pub)
end
+
+ def self.vcall_with_using(x = RefinedClass.new)
+ x.instance_eval {defined?(priv)}
+ end
end
def test_defined_refined_call_without_using
assert(!RefiningModule.call_without_using, "refined public method without using")
end
+ def test_defined_refined_vcall_without_using
+ assert(!RefiningModule.vcall_without_using, "refined private method without using")
+ end
+
def test_defined_refined_call_with_using
assert(RefiningModule.call_with_using, "refined public method with using")
end
+
+ def test_defined_refined_vcall_with_using
+ assert(RefiningModule.vcall_with_using, "refined private method with using")
+ end
end
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index f910c036f1..f8936b33c5 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3651,12 +3651,9 @@ vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_
}
case DEFINED_FUNC:
klass = CLASS_OF(v);
- if (rb_method_boundp(klass, SYM2ID(obj), 0)) {
+ if (rb_ec_obj_respond_to(ec, v, SYM2ID(obj), TRUE)) {
expr_type = DEFINED_METHOD;
}
- else {
- expr_type = check_respond_to_missing(obj, v);
- }
break;
case DEFINED_METHOD:{
VALUE klass = CLASS_OF(v);
diff --git a/vm_method.c b/vm_method.c
index a87a8f360c..f1b71a181c 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -2358,6 +2358,12 @@ int
rb_obj_respond_to(VALUE obj, ID id, int priv)
{
rb_execution_context_t *ec = GET_EC();
+ return rb_ec_obj_respond_to(ec, obj, id, priv);
+}
+
+int
+rb_ec_obj_respond_to(rb_execution_context_t *ec, VALUE obj, ID id, int priv)
+{
VALUE klass = CLASS_OF(obj);
int ret = vm_respond_to(ec, klass, obj, id, priv);
if (ret == -1) ret = basic_obj_respond_to(ec, obj, id, !priv);