wasm-c-api
wasm-c-api copied to clipboard
sigsegv when trying to access exported memory
own<Trap> trap;
auto instance = Instance::make(store.get(), module.get(), imports, &trap);
if (trap) {
PrintTrap(trap);
return 1;
}
auto memory = instance.get()->exports()[0]->memory();
assert(memory->kind() == wasm::EXTERN_MEMORY); // SIGSEGV here
backtrace:
(lldb) bt
* thread #1, name = 'weed8', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
* frame #0: 0x0000555556859158 weed8`v8::internal::FullObjectSlot::operator*() const at slots-inl.h:32:64
frame #1: 0x000055555686e3bd weed8`v8::internal::Handle<v8::internal::JSReceiver> const v8::internal::Handle<v8::internal::JSReceiver>::cast<v8::internal::JSReceiver>(v8::internal::Handle<v8::internal::JSReceiver>) at handles-inl.h:28:11
frame #2: 0x000055555684fd50 weed8`wasm::RefImpl<wasm::Extern, v8::internal::JSReceiver>::v8_object() const at c-api.cc:761:48
frame #3: 0x00005555568423ed weed8`wasm::Extern::kind() const at c-api.cc:1116:46
frame #4: 0x0000555556838bac weed8`weed8::run(char const*) at weed8.cc:134:3
module is
(module
(import "wasi_unstable" "fd_write" (func $fd_write (param i32) (param i32) (param i32) (result i32)))
(memory (export "memory") 1)
(data (i32.const 16)
"Hello, World"
)
(func $start
(i32.store (i32.const 0) (i32.const 12)) ;; length of data at 16
(i32.store (i32.const 4) (i32.const 16)) ;; pointer to data at 16
(call $fd_write (i32.const 1) (i32.const 0) (i32.const 1))
(drop)
)
(export "start" (func $start))
)
Thanks for the bug report. From the stack trace it looks like you are using V8's native implementation of the API. In that case, please file this bug with V8's bug tracker.
Nope, not a V8 bug; it's a footgun in the API design. instance.get()->exports()
gives you an ownvec<Extern>
, so right after you do [0]->
on it the ownvec
, being a temporary value, goes out of scope and destroys all the Extern
s it contained.
As long as the API doesn't change (and, to be fair, I don't have a good suggestion for how to avoid this footgun there), the client-side solution is to explicitly store the ownvec
in a variable with sufficient lifetime, for example:
ownvec<Extern> exports = instance.get()->exports();
auto memory = exports[0]->memory();