-
Notifications
You must be signed in to change notification settings - Fork 824
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
feat(c-api) Implement wasi_get_unordered_imports
#2053
feat(c-api) Implement wasi_get_unordered_imports
#2053
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it! But I'm hesitant to add new APIs that users may use without a lot of thought as we'll be stuck with them for a while
wasi_get_unordered_imports
wasi_get_unordered_imports
(TASK-4)
wasi_get_unordered_imports
(TASK-4)wasi_get_unordered_imports
Well, in an ideal world, we would need an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot to unpack here, this is my initial review; I'll need to do another pass about ownership / see more examples of the ownership in action (maybe we need a test using these new functions to do something)
r#extern: Box::new(wasm_extern_t { | ||
instance: None, | ||
inner: extern_inner, | ||
}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: review instance: None
, aren't wasm_extern_t
s callable? is instance: None
a problem for data being passed to the user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have an access to Instance
here since we read the externs from Module
.
wasm_extern_t
is defined as:
pub struct wasm_extern_t {
// this is how we ensure the instance stays alive
pub(crate) instance: Option<Arc<Instance>>,
pub(crate) inner: Extern,
}
We don't need to ensure that Instance
stays alive, it doesn't exist at this step :-).
lib/c-api/wasmer.h
Outdated
#if defined(WASMER_EMSCRIPTEN_ENABLED) | ||
/** | ||
* Convenience function for setting up arguments and calling the Emscripten | ||
* main function. | ||
* | ||
* WARNING: | ||
* | ||
* Do not call this function on untrusted code when operating without | ||
* additional sandboxing in place. | ||
* Emscripten has access to many host system calls and therefore may do very | ||
* bad things. | ||
*/ | ||
wasmer_result_t wasmer_emscripten_call_main(wasmer_instance_t *instance, | ||
const wasmer_byte_array *args, | ||
unsigned int args_len); | ||
#endif | ||
|
||
#if defined(WASMER_EMSCRIPTEN_ENABLED) | ||
/** | ||
* Destroy `wasmer_emscrpten_globals_t` created by | ||
* `wasmer_emscripten_get_emscripten_globals`. | ||
*/ | ||
void wasmer_emscripten_destroy_globals(wasmer_emscripten_globals_t *globals); | ||
#endif | ||
|
||
#if defined(WASMER_EMSCRIPTEN_ENABLED) | ||
/** | ||
* Create a `wasmer_import_object_t` with Emscripten imports, use | ||
* `wasmer_emscripten_get_emscripten_globals` to get a | ||
* `wasmer_emscripten_globals_t` from a `wasmer_module_t`. | ||
* | ||
* WARNING: | ||
* | ||
* This `import_object_t` contains thin-wrappers around host system calls. | ||
* Do not use this to execute untrusted code without additional sandboxing. | ||
*/ | ||
wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals); | ||
#endif | ||
|
||
#if defined(WASMER_EMSCRIPTEN_ENABLED) | ||
/** | ||
* Create a `wasmer_emscripten_globals_t` from a Wasm module. | ||
*/ | ||
wasmer_emscripten_globals_t *wasmer_emscripten_get_globals(const wasmer_module_t *module); | ||
#endif | ||
|
||
#if defined(WASMER_EMSCRIPTEN_ENABLED) | ||
/** | ||
* Execute global constructors (required if the module is compiled from C++) | ||
* and sets up the internal environment. | ||
* | ||
* This function sets the data pointer in the same way that | ||
* [`wasmer_instance_context_data_set`] does. | ||
*/ | ||
wasmer_result_t wasmer_emscripten_set_up(wasmer_instance_t *instance, | ||
wasmer_emscripten_globals_t *globals); | ||
#endif | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to commit these deletions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I didn't know why they were still here. As far as I know, our C API no longer ship with emscripten, is that right?
* Non-standard function to get the module name of a | ||
* `wasm_named_extern_t`. | ||
*/ | ||
const wasm_name_t *wasm_named_extern_module(const wasm_named_extern_t *named_extern); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be a wider problem but we need to mark things as own
in our extension to the Wasm C API, otherwise it's really hard impossible to know what needs to be freed by who
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. I just don't know how to add attributes inside the C headers from Rust. I'm not even sure if it's doable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll explain that in the documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in this case, ownership isn't transferred by the way)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While documenting onwership, I found a memory leak. We said in wasi_get_imports
and in wasi_get_unordered_imports
that the ownership of the wasi_env_t
parameter is taken by the function, which wasn't the case. It was memory leak.
It's not fixed.
Edit: see 9e63ba9.
This patch also moves `wasm_extern_delete` into the correct Rust module.
8d842f7
to
0861b73
Compare
In `wasi_get_imports` and `wasi_get_unordered_imports`, we said the ownership of `wasi_env_t` was taken by the function, but it wasn't the case. This patch changes the type from `&wasi_env_t` to `Box<wasi_env_t>` to take ownership of it. The rest of the patch updates the documentation, and improves null protections with `Option<T>`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, if there are any problems with this I'm not able to see them right now!
I did become aware again that we're using unsafe
in a lot of places that we don't need to, but we can fix that separately
2074: feat(package) Be consistent on Windows regarding `libwasmer` name. r=jubianchi a=Hywan # Description Windows package libraries aren't named consistently regarding other platforms. This patch fixes that. # Review - [ ] Add a short description of the the change to the CHANGELOG.md file 2083: doc(c-api) Remove inline documentation in `wasmer_wasm.h`, clarification about stability… r=Hywan a=Hywan # Description As suggested in #2053 (comment), this PR removes the automatically generated documentation when building `wasmer_wasm.h`. It also clarifies our position regarding stability, and add a section about the documentation. This PR takes also the opportunity to mark `wasi_env_set_(instance|memory)` as deprecated functions. # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Ivan Enderlin <[email protected]>
bors r+ |
2053: feat(c-api) Implement `wasi_get_unordered_imports` r=Hywan a=Hywan Depend on #2083. # Description The problem I've with the C API for WASI is the following: ```c // At some point, we write this: bool success = wasi_get_imports(store, module, wasi_env, &imports_to_collect); ``` This function iterates over the module imports, and for each entry, it looks inside the (inner generated) WASI import object if a matching entry exists. If it doesn't, it fails. See: https://github.com/wasmerio/wasmer/blob/6b028410c23da088d62a6b6919e2c086931ad101/lib/c-api/src/wasm_c_api/wasi/mod.rs#L333-L356 So… if a module requires WASI and WASI only, it works like a charm of course. But, if a module requires WASI + other imports, it will fail. And I think it's a common pattern to use WASI + some other imports (like `math.random` or anything related to I/O etc etc.). What we need is an API to collect all the WASI imports, in no particular order, by module/namespace and name, so that we can implement an API like `ImportObject` to re-order the imports when needed (i.e. when passing a vec of externs to `wasm_instance_new` for example). # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Ivan Enderlin <[email protected]>
Build failed: |
2083: doc(c-api) Remove inline documentation in `wasmer_wasm.h`, clarification about stability… r=Hywan a=Hywan # Description As suggested in #2053 (comment), this PR removes the automatically generated documentation when building `wasmer_wasm.h`. It also clarifies our position regarding stability, and add a section about the documentation. This PR takes also the opportunity to mark `wasi_env_set_(instance|memory)` as deprecated functions. # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Ivan Enderlin <[email protected]>
2083: doc(c-api) Remove inline documentation in `wasmer_wasm.h`, clarification about stability… r=Hywan a=Hywan # Description As suggested in #2053 (comment), this PR removes the automatically generated documentation when building `wasmer_wasm.h`. It also clarifies our position regarding stability, and add a section about the documentation. This PR takes also the opportunity to mark `wasi_env_set_(instance|memory)` as deprecated functions. # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Ivan Enderlin <[email protected]>
2083: doc(c-api) Remove inline documentation in `wasmer_wasm.h`, clarification about stability… r=Hywan a=Hywan # Description As suggested in #2053 (comment), this PR removes the automatically generated documentation when building `wasmer_wasm.h`. It also clarifies our position regarding stability, and add a section about the documentation. This PR takes also the opportunity to mark `wasi_env_set_(instance|memory)` as deprecated functions. # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Ivan Enderlin <[email protected]>
2083: doc(c-api) Remove inline documentation in `wasmer_wasm.h`, clarification about stability… r=Hywan a=Hywan # Description As suggested in #2053 (comment), this PR removes the automatically generated documentation when building `wasmer_wasm.h`. It also clarifies our position regarding stability, and add a section about the documentation. This PR takes also the opportunity to mark `wasi_env_set_(instance|memory)` as deprecated functions. # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Ivan Enderlin <[email protected]>
… nightly. So. Let's explain a dirty hack. `cbindgen` reads the code and collects symbols. What symbols do we need? None of the one declared in `wasm.h`, but for non-standard API, we need to collect all of them. The problem is that `wasm_named_extern_t` is the only non-standard type where extra symbols are generated by a macro (`wasm_declare_boxed_vec!`). If we want those macro-generated symbols to be collected by `cbindgen`, we need to _expand_ the crate (i.e. running something like `rustc -- -Zunstable-options --pretty=expanded`). Expanding code is unstable and available only on nightly compiler. We _don't want_ to use a nightly compiler only for that. So how can we help `cbindgen` to _see_ those symbols? First solution: We write the C code directly in a file, which is then included in the generated header file with the `cbindgen` API. Problem, it's super easy to get it outdated, and it makes the build process more complex. Second solution: We write those symbols in a custom module, that is just here for `cbindgen`, never used by our Rust code (otherwise it's duplicated code), with no particular implementation. And that's why we have the following `cbindgen_hack` module. But this module must not be compiled by `rustc`. How to force `rustc` to ignore a module? With conditional compilation. Because `cbindgen` does not support conditional compilation, it will always _ignore_ the `#[cfg]` attribute, and will always read the content of the module. Sorry.
bors try |
tryBuild failed: |
We said that `wasi_get_imports` was taking ownership of `wasi_env_t`. It wasn't. In 9e63ba9, we have fixed this. But it creates another bug when `wasi_env_t` is used _after_ for example when calling `wasi_env_read_stdout`. So this patch reverts the bug fix. And we will discuss about how to fix that later.
bors r+ |
Depend on #2083.
Description
The problem I've with the C API for WASI is the following:
This function iterates over the module imports, and for each entry, it looks inside the (inner generated) WASI import object if a matching entry exists. If it doesn't, it fails. See:
wasmer/lib/c-api/src/wasm_c_api/wasi/mod.rs
Lines 333 to 356 in 6b02841
So… if a module requires WASI and WASI only, it works like a charm of course.
But, if a module requires WASI + other imports, it will fail.
And I think it's a common pattern to use WASI + some other imports (like
math.random
or anything related to I/O etc etc.).What we need is an API to collect all the WASI imports, in no particular order, by module/namespace and name, so that we can implement an API like
ImportObject
to re-order the imports when needed (i.e. when passing a vec of externs towasm_instance_new
for example).Review