-
Notifications
You must be signed in to change notification settings - Fork 259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A host function that calls another host function loses access to the memory #1626
Comments
I've looked a bit into this. I built invoke_host.wasm.zip according to instructions. With the compiler I can't get into the second call into To fix that I needed to add the following to the top of func (ce *callEngine) execWasmFunction(ctx context.Context, m *wasm.ModuleInstance) {
codeAddr := ce.initialFn.codeInitialAddress
modAddr := ce.initialFn.moduleInstance
if ce.initialFn.parent.goFunc != nil {
calleeHostFunction := ce.moduleContext.fn
base := int(ce.stackBasePointerInBytes >> 3)
// In the compiler engine, ce.stack has enough capacity for the
// max of param or result length, so we don't need to grow when
// there are more results than parameters.
stackLen := calleeHostFunction.funcType.ParamNumInUint64
if resultLen := calleeHostFunction.funcType.ResultNumInUint64; resultLen > stackLen {
stackLen = resultLen
}
stack := ce.stack[base : base+stackLen]
fn := calleeHostFunction.parent.goFunc
switch fn := fn.(type) {
case api.GoModuleFunction:
fn.Call(ctx, modAddr, stack)
case api.GoFunction:
fn.Call(ctx, stack)
}
return
}
entry: Then I can repro with both compiler or interpreter. I couldn't get the appropriate This is as far as I got. Can't go much further down, doesn't look like a simple fix. |
If the fix isn't so simple, I have thought of this workaround for now: It at least fixes the issue I had while implementing Emscripten C++ Exceptions because both host functions are within the same package. It won't fix the issue reported in the example because I won't be able to get the parent callee module from the context, but I don't think it will be a common issue, I had to make some specific code to make the invoke_xxx call another host method, while in C++ exception handling it's a common occurrence. Here is the full implementation: |
verified that #1636 fixes the repro:
|
Describe the bug
So I'm not entirely sure this is a bug report or a feature request. I came across this issue while implementing C++ exceptions support for Emscripten in Wazero. Apparently it's possible that Emscripten uses the generated invoke_xxx methods (which is a host function) to call another host function, without a "proxy" through the guest. I then found out that it's also possible to reproduce it without using C++ exceptions.
This issue causes the second host function not to have access to the memory, because the second host function is being called by invoke_xxx, which is in the env module, and receives the env
api.Module
, while the invoke_xxx is also in the env module, it does receive the main application memory, and this is also mentioned in the comments ofGoModuleFunction
:While it does make sense to give this the caller's memory (if we didn't, the host functions would be way less usable), but in my case, this means that the second host function call does not have access to the memory, just because it was called from another host method and not from the guest, while it would have access to it if it would have been called by a "proxy" function in the guest.
I'm not sure what the best solution to this would be. Perhaps it would be possible to have an option to override the moduleInstance or memoryInstance in
m.Engine.LookupFunction
orf.CallWithStack
so that we can use it inInvokeFunc.Call()
to maintain access to the memory when doing host to host calls.Given the sample code in the next block, the following two things will happen:
Works 🎉
Breaks 💣 (
failed: runtime error: invalid memory address or nil pointer dereference
)To Reproduce
C code compiled with Emscripten
emcc -sERROR_ON_UNDEFINED_SYMBOLS=0 -sSUPPORT_LONGJMP=emscripten -g invoke_host.c -o invoke_host.wasm
Go code with the host function implemented
Full sample zip:
invoke_host.zip
Environment (please complete the relevant information):
Additional context
This was also discussed a bit on Slack: https://gophers.slack.com/archives/C040AKTNTE0/p1691699092428169
The text was updated successfully, but these errors were encountered: