-
Notifications
You must be signed in to change notification settings - Fork 825
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
Changes from 13 commits
a4effaa
e10ad51
75ceb0d
a3c7a2d
a0c34fe
4abf6f8
43026e6
940dea7
8aa0822
96169de
eb03f18
2853bd4
272b9d1
51fe219
a68a1e6
40fa9c0
2ca30fe
b9afb6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,31 @@ | |
macro_rules! wasm_declare_vec_inner { | ||
($name:ident) => { | ||
paste::paste! { | ||
/// Creates an empty vector of | ||
#[doc = "Creates an empty vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Creates an empty vector of [`wasm_" $name "_t`]. | ||
|
||
# Example | ||
|
||
```rust | ||
# use inline_c::assert_c; | ||
# fn main() { | ||
# (assert_c! { | ||
# #include \"tests/wasmer_wasm.h\" | ||
# | ||
int main() { | ||
// Creates an empty vector of `wasm_" $name "_t`. | ||
wasm_" $name "_vec_t vector; | ||
wasm_" $name "_vec_new_empty(&vector); | ||
|
||
// Check that it is empty. | ||
assert(vector.size == 0); | ||
|
||
// Free it. | ||
wasm_" $name "_vec_delete(&vector); | ||
} | ||
# }) | ||
# .success(); | ||
# } | ||
```"] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn [<wasm_ $name _vec_new_empty>](out: *mut [<wasm_ $name _vec_t>]) { | ||
// TODO: actually implement this | ||
|
@@ -19,7 +42,37 @@ macro_rules! wasm_declare_vec_inner { | |
macro_rules! wasm_declare_vec { | ||
($name:ident) => { | ||
paste::paste! { | ||
#[doc = "Represents of a vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Represents a vector of `wasm_" $name "_t`. | ||
|
||
Read the documentation of [`wasm_" $name "_t`] to see more concrete examples. | ||
|
||
# Example | ||
|
||
```rust | ||
# use inline_c::assert_c; | ||
# fn main() { | ||
# (assert_c! { | ||
# #include \"tests/wasmer_wasm.h\" | ||
# | ||
int main() { | ||
// Create a vector of 2 `wasm_" $name "_t`. | ||
wasm_" $name "_t x; | ||
wasm_" $name "_t y; | ||
wasm_" $name "_t* items[2] = {&x, &y}; | ||
|
||
wasm_" $name "_vec_t vector; | ||
wasm_" $name "_vec_new(&vector, 2, (wasm_" $name "_t*) items); | ||
|
||
// Check that it contains 2 items. | ||
assert(vector.size == 2); | ||
|
||
// Free it. | ||
wasm_" $name "_vec_delete(&vector); | ||
} | ||
# }) | ||
# .success(); | ||
# } | ||
```"] | ||
#[derive(Debug)] | ||
#[repr(C)] | ||
pub struct [<wasm_ $name _vec_t>] { | ||
|
@@ -54,6 +107,7 @@ macro_rules! wasm_declare_vec { | |
.into_boxed_slice(); | ||
let data = copied_data.as_mut_ptr(); | ||
::std::mem::forget(copied_data); | ||
|
||
Self { | ||
size, | ||
data, | ||
|
@@ -84,31 +138,68 @@ macro_rules! wasm_declare_vec { | |
} | ||
|
||
// TODO: investigate possible memory leak on `init` (owned pointer) | ||
#[doc = "Creates a new vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Creates a new vector of [`wasm_" $name "_t`]. | ||
|
||
# Example | ||
|
||
See the [`wasm_" $name "_vec_t`] type to get an example."] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *mut [<wasm_ $name _t>]) { | ||
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length); | ||
|
||
for i in 0..length { | ||
bytes.push(::std::ptr::read(init.add(i))); | ||
} | ||
|
||
let pointer = bytes.as_mut_ptr(); | ||
debug_assert!(bytes.len() == bytes.capacity()); | ||
|
||
(*out).data = pointer; | ||
(*out).size = length; | ||
::std::mem::forget(bytes); | ||
} | ||
|
||
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`]. | ||
|
||
# Example | ||
|
||
```rust | ||
# use inline_c::assert_c; | ||
# fn main() { | ||
# (assert_c! { | ||
# #include \"tests/wasmer_wasm.h\" | ||
# | ||
int main() { | ||
// Creates an empty vector of `wasm_" $name "_t`. | ||
wasm_" $name "_vec_t vector; | ||
wasm_" $name "_vec_new_uninitialized(&vector, 3); | ||
|
||
// Check that it contains 3 items. | ||
assert(vector.size == 3); | ||
|
||
// Free it. | ||
wasm_" $name "_vec_delete(&vector); | ||
} | ||
# }) | ||
# .success(); | ||
# } | ||
```"] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) { | ||
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length); | ||
let pointer = bytes.as_mut_ptr(); | ||
|
||
(*out).data = pointer; | ||
(*out).size = length; | ||
|
||
::std::mem::forget(bytes); | ||
} | ||
|
||
#[doc = "Deletes a vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Deletes a vector of [`wasm_" $name "_t`]. | ||
|
||
# Example | ||
|
||
See the [`wasm_" $name "_vec_t`] type to get an example."] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: Option<&mut [<wasm_ $name _vec_t>]>) { | ||
if let Some(vec) = ptr { | ||
|
@@ -130,7 +221,9 @@ macro_rules! wasm_declare_vec { | |
macro_rules! wasm_declare_boxed_vec { | ||
($name:ident) => { | ||
paste::paste! { | ||
#[doc = "Represents of a vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Represents a vector of `wasm_" $name "_t`. | ||
|
||
Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."] | ||
#[derive(Debug)] | ||
#[repr(C)] | ||
pub struct [<wasm_ $name _vec_t>] { | ||
|
@@ -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>] { | ||
fn from(other: &'a [T]) -> Self { | ||
let size = other.len(); | ||
let mut copied_data = other | ||
.iter() | ||
.cloned() | ||
.map(Into::into) | ||
.map(Box::new) | ||
.map(Box::into_raw) | ||
.collect::<Vec<*mut [<wasm_ $name _t>]>>() | ||
.into_boxed_slice(); | ||
let data = copied_data.as_mut_ptr(); | ||
::std::mem::forget(copied_data); | ||
|
||
Self { | ||
size, | ||
data, | ||
} | ||
} | ||
} | ||
|
||
// TODO: do this properly | ||
impl [<wasm_ $name _vec_t>] { | ||
pub unsafe fn into_slice(&self) -> Option<&[Box<[<wasm_ $name _t>]>]>{ | ||
|
@@ -171,33 +285,75 @@ macro_rules! wasm_declare_boxed_vec { | |
#[no_mangle] | ||
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *const *mut [<wasm_ $name _t>]) { | ||
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length); | ||
|
||
for i in 0..length { | ||
bytes.push(*init.add(i)); | ||
} | ||
|
||
let pointer = bytes.as_mut_ptr(); | ||
debug_assert!(bytes.len() == bytes.capacity()); | ||
|
||
(*out).data = pointer; | ||
(*out).size = length; | ||
|
||
::std::mem::forget(bytes); | ||
} | ||
|
||
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`]. | ||
|
||
# Example | ||
|
||
```rust | ||
# use inline_c::assert_c; | ||
# fn main() { | ||
# (assert_c! { | ||
# #include \"tests/wasmer_wasm.h\" | ||
# | ||
int main() { | ||
// Creates an empty vector of `wasm_" $name "_t`. | ||
wasm_" $name "_vec_t vector; | ||
wasm_" $name "_vec_new_uninitialized(&vector, 3); | ||
|
||
// Check that it contains 3 items. | ||
assert(vector.size == 3); | ||
|
||
// Free it. | ||
wasm_" $name "_vec_delete(&vector); | ||
} | ||
# }) | ||
# .success(); | ||
# } | ||
```"] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) { | ||
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length); | ||
let pointer = bytes.as_mut_ptr(); | ||
|
||
(*out).data = pointer; | ||
(*out).size = length; | ||
|
||
::std::mem::forget(bytes); | ||
} | ||
|
||
#[doc = "Deletes a vector of [`wasm_" $name "_t`]."] | ||
#[doc = "Deletes a vector of [`wasm_" $name "_t`]. | ||
|
||
# Example | ||
|
||
See the [`wasm_" $name "_vec_t`] type to get an example."] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: *mut [<wasm_ $name _vec_t>]) { | ||
Hywan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let vec = &mut *ptr; | ||
Hywan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if !vec.data.is_null() { | ||
let data: Vec<*mut [<wasm_ $name _t>]> = Vec::from_raw_parts(vec.data, vec.size, vec.size); | ||
let _data: Vec<Box<[<wasm_ $name _t>]>> = ::std::mem::transmute(data); | ||
|
||
// 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); | ||
Hywan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 |
||
|
||
vec.data = ::std::ptr::null_mut(); | ||
vec.size = 0; | ||
} | ||
|
@@ -222,7 +378,6 @@ macro_rules! wasm_declare_ref_base { | |
} | ||
|
||
// TODO: finish this... | ||
|
||
} | ||
}; | ||
} | ||
|
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.