-
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
test+doc(c-api) Fix vecs that must be boxed vecs + don't transmute uninitialized boxed vecs #1949
Conversation
In `wasm.h`, `wasm_functype_t` is implemented with `WASM_DECLARE_TYPE`, so with `WASM_DECLARE_VEC(functype, *)`. This `*` means the C struct for the vector is defined: ```c struct wasm_functype_vec_t { size_t size; wasm_functype_t** data; } ``` The way we implement `wasm_functype_vec_t` in Rust is with the `wasm_declare_vec!` macro. And it is wrong. We must use `wasm_declared_boxed_vec!`.
In `wasm.h`, `wasm_globaltype_t` is implemented with `WASM_DECLARE_TYPE`, so with `WASM_DECLARE_VEC(globaltype, *)`. This `*` means the C struct for the vector is defined: ```c struct wasm_globaltype_vec_t { size_t size; wasm_globaltype_t** data; } ``` The way we implement `wasm_globaltype_vec_t` in Rust is with the `wasm_declare_vec!` macro. And it is wrong. We must use `wasm_declared_boxed_vec!`.
In `wasm.h`, `wasm_memorytype_t` is implemented with `WASM_DECLARE_TYPE`, so with `WASM_DECLARE_VEC(memorytype, *)`. This `*` means the C struct for the vector is defined: ```c struct wasm_memorytype_vec_t { size_t size; wasm_memorytype_t** data; } ``` The way we implement `wasm_memorytype_vec_t` in Rust is with the `wasm_declare_vec!` macro. And it is wrong. We must use `wasm_declared_boxed_vec!`.
In `wasm.h`, `wasm_tabletype_t` is implemented with `WASM_DECLARE_TYPE`, so with `WASM_DECLARE_VEC(tabletype, *)`. This `*` means the C struct for the vector is defined: ```c struct wasm_tabletype_vec_t { size_t size; wasm_tabletype_t** data; } ``` The way we implement `wasm_tabletype_vec_t` in Rust is with the `wasm_declare_vec!` macro. And it is wrong. We must use `wasm_declared_boxed_vec!`.
In `wasm.h`, `wasm_frame_t` is implemented with `WASM_DECLARE_TYPE`, so with `WASM_DECLARE_VEC(frame, *)`. This `*` means the C struct for the vector is defined: ```c struct wasm_frame_vec_t { size_t size; wasm_frame_t** data; } ``` The way we implement `wasm_frame_vec_t` in Rust is with the `wasm_declare_vec!` macro. And it is wrong. We must use `wasm_declared_boxed_vec!`.
In case of a boxed vector, `wasm_$name_vec_delete` now checks that the vec is correctly initialized (by checking the first item only) because transmuting `Vec<*mut T>` to `Vec<Box<T>>`, otherwise it will crash.
@@ -153,6 +246,27 @@ macro_rules! wasm_declare_boxed_vec { | |||
} | |||
} | |||
|
|||
impl<'a, T: Into<[<wasm_ $name _t>]> + Clone> From<&'a [T]> for [<wasm_ $name _vec_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.
Such implementation exists for regular vecs. Now it exists for boxed vecs too.
lib/c-api/src/wasm_c_api/macros.rs
Outdated
// If the vector has been initialized (we check | ||
// only the first item), we can transmute items to | ||
// `Box`es. | ||
if vec.size > 0 && !data[0].is_null() { | ||
let _data: Vec<Box<[<wasm_ $name _t>]>> = ::std::mem::transmute(data); | ||
} |
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 changes allows to delete an uninitialized boxed vec. Should we check for all items or checking the first is safe enough?
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.
For handling uninitialized, I think we just have to make a representation of uninit
that makes sense... I think the code as-is will break in real code (for example partially initialized vectors. I'll get back to you with more details after finishing the review and looking at the code locally
bors try |
tryBuild failed: |
Too bad, it's working on |
Following Notice the difference with Ideally, the We could probably just used |
lib/c-api/src/wasm_c_api/macros.rs
Outdated
// If the vector has been initialized (we check | ||
// only the first item), we can transmute items to | ||
// `Box`es. | ||
if vec.size > 0 && !data[0].is_null() { | ||
let _data: Vec<Box<[<wasm_ $name _t>]>> = ::std::mem::transmute(data); | ||
} |
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.
For handling uninitialized, I think we just have to make a representation of uninit
that makes sense... I think the code as-is will break in real code (for example partially initialized vectors. I'll get back to you with more details after finishing the review and looking at the code locally
How do I reproduce the failure? Locally |
…n<&mut T>`. This was already the case for regular vec. This patch applies the same pattern for boxed vec. See wasmerio@deec77d.
It's a safer way to handle partially uninitialized boxed vector, since it protects against based deletion for every item.
To handle partially uninitialized boxed vector, I propose to transmute the |
This patch updates how `wasm_$name_vec_new_uninitialized` creates the vector. The vector is now fully allocated with `null` pointer for each item, instead of having an empty vector with the initial capacity set to `length`. That way, we are sure the vector is zeroed correctly.
bors try |
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 have some other small comments but it overlaps with #1944, and I can change them there!
wasm_valtype_vec_delete(Some(params.as_mut())); | ||
wasm_valtype_vec_delete(Some(results.as_mut())); | ||
|
||
mem::forget(params); | ||
mem::forget(results); |
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.
Ideally, we'd have Drop
implemented and it'd do this for us
bors r+ |
1953: Get `multi.c` working in the Wasm C API r=MarkMcCaskey a=MarkMcCaskey Gets the `multi.c` example working. This PR has significant overlap with #1949 due to changes in vec / boxed vec. Changes in this PR: - impl `Clone` more often, implement `*_copy` functions in terms of `Clone` - clean up boxed vec behavior - add `*_vec_copy` functions for boxed and unboxed versions - fix a typo in `wasm-c-api/examples/multi.c`; fixed in the upstream Wasm C API here: WebAssembly/wasm-c-api#163 - additional misc improvements # Review - [ ] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Mark McCaskey <[email protected]> Co-authored-by: Mark McCaskey <[email protected]>
Description
This PR improve test coverage of the C API.
It's a work in progress. I've paused this work because we need to focus on something else, but one of the two test cases that have been added reveals an important bug.The
wasm_frame_vec_t
,wasm_functype_vec_t
,wasm_globaltype_vec_t
,wasm_memorytype_vec_t
andwasm_tabletype_vec_t
are incorrectly defined. Indeed, inwasm.h
they are all defined withWASM_DECLARE_TYPE
(except forwasm_frame_vec_t
, but it's exactly the same), which declares the vectors asWAM_DECLARE_VEC(name, *)
. This*
is important. It means that we must not declare thoses types with our ownwasm_declare_vec!
macro, but rather withwasm_declare_boxed_vec!
.Fixing this bug impact many places in the code. I didn't have time for the moment, but it's probably not a big deal!This PR fixes those bugs with e10ad51, 75ceb0d, a3c7a2d, a0c34fe. Bonus forwasm_frame_t
that was also incorrectly implemented, the fix lands in 4abf6f8 and is possible thanks to 43026e6, with a side effect of simplifying the code in 940dea7.While continuing to improve the test coverage, another bug has been found. In case of a boxed vector,
wasm_$name_vec_delete
was crashing if the given vector was uninitialized. Basically the following code was crashing:This is now fixed in 8aa0822, and tested in 96169de.
The PR adds 34 test cases, and has found+fixes 6 bugs.
Review