Bug #11214
closedCannot Get Correct Binding from inside of C Method
Description
I am trying to get the arguments passed into a method using the binding. This is possible using pure Ruby:
class RubyBindingClass
def foo(arg = nil)
return binding
end
end
binding = RubyBindingClass.new.foo
puts binding.eval("self")
# => #<RubyBindingClass:0x007fdc5224f7f8>
puts binding.local_variables.inspect
# => [arg]
You can see that the #<RubyBindingClass:0x007fdc5224f7f8>
is returned as self and the local_variables
correctly reports that arg
is in scope. When we access the binding from a C method, we do not get the same information
# Thanks to Frederick Cheung for the code snippet
require 'inline' # $ gem install RubyInline
random_main_variable = 2
class CBindingClass
inline do |builder|
builder.include "<time.h>"
builder.c_raw <<-SRC, :arity => 1
VALUE foo(VALUE self, VALUE arg){
VALUE ret = rb_funcall(self, rb_intern("binding"), 0);
return ret;
}
SRC
end
end
binding = CBindingClass.new.foo(10)
puts binding.eval("self")
# => main
puts binding.local_variables.inspect
# => [:binding, :random_main_variable]
Here you can see that self is reported as main
and that local_variables
is returning variables from the main scope instead of from within the C method.
I originally stumbled upon this while trying to get access to arguments via TracePoint: http://stackoverflow.com/questions/30584454/get-method-arguments-using-rubys-tracepoint. Is this binding behavior intentional? Should it be possible to get programatic access to arguments passed into a C defined method?
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
- Status changed from Open to Feedback
I'm fairly sure having binding
capture arguments passed to C methods is not possible. Ruby doesn't know the C function's parameter names at runtime. Even if that were possible, you wouldn't be able to handle cases where a C function takes a variable number of arguments (VALUE func(int argc, VALUE *argv, VALUE self)
). So that's why the binding does not include C-level information. It is similar to not being able to get the parameter names for methods defined in C via Method#parameters
.
In terms of why binding
returns variables from the surrounding scope if called from C, I'm not sure. I think the only alternative would be raising an exception. I'm guessing we don't want to change the behavior, as there are libraries that appear to be relying on it:
- https://github.com/FluxAugur/danddnext/blob/e0c4371527569970243ca1a76768ae0ced015474/vendor/gems/interception-0.5/ext/interception.c#L31
- https://github.com/Charo-IT/libgdbruby/blob/3109f4b3da26dbe7d7e723936ce332d7c57353be/libgdbruby/libgdbruby.cpp#L170
- https://github.com/tario/evalmimic/blob/3bf84e38ceb03ffc4fe5cfd41da63bb501e0f118/ext/evalmimic_base/evalmimic_base.c#L35
Do you still consider this a bug?
Updated by chrisseaton (Chris Seaton) over 4 years ago
I'm fairly sure having binding capture arguments passed to C methods is not possible.
TruffleRuby could do that! Sorry I know it's boasting and not relevant to MRI :)
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
- Status changed from Feedback to Closed