go-mruby
go-mruby copied to clipboard
mruby.Run does not work with a Proc returned from LoadString
mrb := NewMrb()
defer mrb.Close()
proc, _ := mrb.LoadString(`
Proc.new do
puts 1
end
`)
val, err := mrb.Run(proc, nil)
fmt.Printf("%#v, %#v", val, err)
Expected: Prints "1", returns nil, nil Actual: (_mruby.MrbValue)(nil), &mruby.Exception{MrbValue:(_mruby.MrbValue)(0xc8200920e0), cachedString:"unexpected return"}
For some reason mruby.Run does not work with a Proc returned from mruby.LoadString. There may be good technical reasons (though I can't think of what they might be) but this surprised me. The error unexpected return is also non-obvious as there is no return injected anywhere AFAICT.
It is necessary to use something like the following to create a Proc that works with mruby.Run:
mrb := NewMrb()
defer mrb.Close()
parser := NewParser(mrb)
defer parser.Close()
context := NewCompileContext(mrb)
defer context.Close()
parser.Parse(`puts 1`, context)
proc := parser.GenerateCode()
val, err := mrb.Run(proc, nil)
fmt.Printf("%#v, %#v", val, err)
This works as expected. Drilling down in to the differences between the MrbValues generated with these two approaches should be sufficient to determine a cause (and potential solution).
Pretty odd. I expect its some weirdness with the C API. Steps forward would be:
- Determine if
mrb_runis supposed to work with procs at all. - If yes, fix it!
- If no, ask ourselves why? And determine if go-mruby should "just work".
(Note: not telling you you have to do this, just posting that thats what the steps are in general)
while I was trying to verify this, I ran into a full panic with the following ruby:
def foo
end
The return value is indeed the foo func yet this trace occurs on a recent version of master:
[fail:1][75] erikh@islay erikh/ruby-builder% go run ~/test.go [14:34]
foo
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x2a5 pc=0x40c3bf2]
runtime stack:
runtime.throw(0x4135538, 0x2a)
/usr/local/Cellar/go/1.7.1/libexec/src/runtime/panic.go:566 +0x95
runtime.sigpanic()
/usr/local/Cellar/go/1.7.1/libexec/src/runtime/sigpanic_unix.go:12 +0x2cc
goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x408a750, 0xc42004fe18, 0x0)
/usr/local/Cellar/go/1.7.1/libexec/src/runtime/cgocall.go:131 +0x110 fp=0xc42004fdc8 sp=0xc42004fd88
github.com/mitchellh/go-mruby._Cfunc_mrb_run(0x4402850, 0x28d, 0x48084a0, 0x8, 0x0, 0x0)
??:0 +0x57 fp=0xc42004fe18 sp=0xc42004fdc8
github.com/mitchellh/go-mruby.(*Mrb).Run(0xc420086018, 0x41b2440, 0xc420088060, 0x41b2440, 0xc420088080, 0x4, 0x0, 0x0)
/Users/erikh/src/github.com/mitchellh/go-mruby/mruby.go:193 +0x1b4 fp=0xc42004feb8 sp=0xc42004fe18
main.main()
/Users/erikh/test.go:20 +0x11d fp=0xc42004ff48 sp=0xc42004feb8
runtime.main()
/usr/local/Cellar/go/1.7.1/libexec/src/runtime/proc.go:183 +0x1f4 fp=0xc42004ffa0 sp=0xc42004ff48
runtime.goexit()
/usr/local/Cellar/go/1.7.1/libexec/src/runtime/asm_amd64.s:2086 +0x1 fp=0xc42004ffa8 sp=0xc42004ffa0
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
/usr/local/Cellar/go/1.7.1/libexec/src/runtime/asm_amd64.s:2086 +0x1
exit status 2
@erikh I've replicated it but given that this code already isn't behaving as we anticipated I'm not entirely surprised.
My test case was:
mrb := mruby.NewMrb()
defer mrb.Close()
result, err := mrb.LoadString(`
def foo
end
`)
// mrb.Run(result, nil) // Causes SIGSEGV
fmt.Printf("Result: %#v, %s\n", result, err)
This printed:
Result: &mruby.MrbValue{value:mruby._Ctype_struct_mrb_value{value:[8]uint8{0x8d, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, tt:0x4, _:[4]uint8{0x0, 0x0, 0x0, 0x0}}, state:(*mruby._Ctype_struct_mrb_state)(0x2578760)}, %!s(<nil>)
tt:0x4 field of mrb_value indicates that result contains an MRB_TT_SYMBOL
IRB behaves similarly (returning a symbol from a function declaration):
> irb
irb(main):001:0> def foo
irb(main):002:1> end
=> :foo
I think we'd need to expose / use mrb_f_send to make your test work.
makes sense. I'll see what I can do this week.
On 6 Oct 2016, at 6:53, Mike Simons wrote:
@erikh I've replicated it but given that this code already isn't behaving as we anticipated I'm not entirely surprised.
My test case was:
mrb := mruby.NewMrb() defer mrb.Close() result, err := mrb.LoadString(` def foo end `) // mrb.Run(result, nil) // Causes SIGSEGV fmt.Printf("Result: %#v, %s\n", result, err)This printed:
Result: &mruby.MrbValue{value:mruby._Ctype_struct_mrb_value{value:[8]uint8{0x8d, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, tt:0x4, _:[4]uint8{0x0, 0x0, 0x0, 0x0}}, state:(*mruby._Ctype_struct_mrb_state)(0x2578760)}, %!s(<nil>)
tt:0x4field ofmrb_valueindicates thatresultcontains an mrb_value of type MRB_TT_SYMBOLIRB behaves similarly (returning a symbol from a function declaration):
> irb irb(main):001:0> def foo irb(main):002:1> end => :fooI think we'd need to expose / use mrb_f_send to make your test work.
You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub: https://github.com/mitchellh/go-mruby/issues/23#issuecomment-251967662
Just a note; since such an easy mistake to make can cause a segfault, we should probably inspect the mrbvalue and ensure it's a proc before handing it over to C. Might also be interesting to try this with a more recent version of mruby (I tested against the version in the makefile)