Is this the right place for questions relating to the wasm c-api ? It looks like it's intended to be implementation neutral, but actually lives in the wasmtime repo...
This is the right place to ask about the Wasmtime implementation of the standards-track C API, and about the other C API we provide :smile:
For more context, our implementation of the standards-track C API lives in this repository, while the spec, headers, etc live in the WebAssembly github org. That said, Wasmtime also has another C API for the reasons outlined here: https://github.com/bytecodealliance/rfcs/blob/main/accepted/new-api.md#the-new-wasmtime-c-api
Right, thanks. So my problem is with resolving exported functions. e.g.
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[2]);
To make that work, the sizeof(wasm_extern_t) must be defined, so that the array stride/offset can be calculated. However, that datatype does not appear to be part of the wasm.h header? That seems to rule out dynamically linking (or calling from another language) code that needs to work with such memory layouts?
wasm_extern_vec_t
is declared by WASM_DECLARE_VEC(extern, *)
: https://github.com/WebAssembly/wasm-c-api/blob/c9d31284651b975f05ac27cee0bab1377560b87e/include/wasm.h#L488
Note that the element type is wasm_extern_t*
(a pointer) and not wasm_extern_t
as the second argument to the WASM_DECLARE_VEC
macro is *
. (ptr_or_none
at https://github.com/WebAssembly/wasm-c-api/blob/c9d31284651b975f05ac27cee0bab1377560b87e/include/wasm.h#L79)
Ahh, ok, so I'm missing a level of indirection somewhere. At least I know what to look for now. Thanks!
When running some of the c-api examples, I get errors like 'wasm_global_same is not implemented'. Is this expected?
@Jonathan Halliday I think that may be a bug in our implementation not having that implemented, so feel free to open an issue! We try to at the very least provide all of the symbols from the wasm.h
C API, although we don't necessarily fully implement all of them (they'll panic if they're not implemented)
So there is no text coverage to ensure the examples work on each release? hmm, ok.
There is also a quirk with functions that are provided in the header, as they don't have an implementation in the library. Work outs ok when compiling with c, but if you're using some other language to call the lib using c conventions, you just get an unsatified link problem.
We generally offload testing of the C API to the bindings we have in other languages which have their own tests. We also do not control the wasm.h
header or its source, so we try to have everything implemented but sometimes there's oversights.
https://github.com/bytecodealliance/wasmtime/blob/main/crates/c-api/src/vec.rs#L75 What's the third arg doing here?
The third argument there is the capacity of the vector if that's what you're interested in? The Vec::from_raw_parts
Rust docs can help explain more I think
Ahh, it's copying rather than wrapping. fair enough, thanks.
There are weird things that happen with the c api where writing directly to the data area of a vec is allowed, but can cause problems down the line because the vec rather than the buffer is used in some cases. I assume that's just an unfortunate side-effect of the implementation choices?
Hm I'm not sure what you mean, can you elaborate on what bad may happen?
looks like if I obtain a vec and modify its contents i.e. the array elements of the data in c, the rust code won't necessarily operate on the modified values, as it's not recopying from the buffer, it's just trusting its vec contents, which is now stale?
I think yeah? In general memory management is pretty tricky with these *_vec_t
types, although we've tried to make it clear in Wasmtime's documentation what the ownership requirements are
This is one reason that the wasmtime.h
APIs generally don't use *_vec_t
It's not clear to me that the c api spec prohibits what I'm doing, which would seem to indicate the implementation is buggy then?
Could you gist what you're doing? I think it depends on precisely what you're doing and what APIs you're claling
I'm calling _new_uninitialized, then dereferencing the .data part and setting a value in it, then calling _delete, which blows up with SEGV. Same thing works fine if I supply the data value as a c array for _new, because that path copies it into the vec, whilst writing the array directly doesn't. In actual c those would be equivalent, but because rust is (sometimes) doing a memory copy behind the scenes to build the vec, it's not.
Can you gist the code that you're doing?
sorry but Rust doesn't copy anything with Vec::from_raw_parts
so I don't follow
I thought slice.to_vec was a copy operation?
Yes to_vec
copies the contents, Vec::from_raw_parts
does not. Sorry I don't know precisely what you're talking about, so some reference could would be helpful to dig into
ok, so when I construct a new vec_t by passing in a c array of ptrs, it copies the array, which I can then dispose of. But what disposes of the copy it made? Calling delete will release the struct holding a pointer to that copy+its size, but as far as I can tell not the copy itself?
using the delete method for a *_vec_t
disposes of the contents of the vector, not the struct holding the contents of the vector
take just sets self.data to a null pointer, its doesn't appear to release the memory that self.data points to first, so it's leaking?
take
returns a Vec<T>
to the Rust caller, and that's an owned value which is released when dropped
ahh, so delete calls take, then as delete returns control from rust back to c, the rust runtime will free the Vec?
right yeah
Ahh, interesting language feature, thanks!
So wasm-c-api/example/hello.c seems fine, until I try to wrap it in a loop, whereupon it runs twice and then falls over... https://pastebin.com/wjM2CuBU Any bright ideas?
Can you share the C code?
It's not all c, I'm driving the c api using java's new panama ffi interface. Fun and games until the SEGVs start.
Does wasm_functype_new take ownership of the params and results vecs ? I've got a double-free bug that I think is due to rust's gc disposing of them...
They take ownership, yes
ok. Must have missed that bit in the api docs. Thanks!
nah I think the api docs may not be super great in this regard, I tried to document things but I probably left out places by accident
Is https://github.com/WebAssembly/wasm-c-api/blob/c9d31284651b975f05ac27cee0bab1377560b87e/example/trap.c working as intended? It appears to take a trap from the implementation's internal checks rather than the fail_callback
Last updated: Nov 22 2024 at 16:03 UTC