diff --git a/CHANGELOG.md b/CHANGELOG.md index fda945847cf..6a5c7b6b563 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ ### Fixed +- [#1949](https://github.com/wasmerio/wasmer/pull/1949) `wasm__vec_delete` functions no longer crash when the given vector is uninitialized, in the Wasmer C API +- [#1949](https://github.com/wasmerio/wasmer/pull/1949) The `wasm_frame_vec_t`, `wasm_functype_vec_t`, `wasm_globaltype_vec_t`, `wasm_memorytype_vec_t`, and `wasm_tabletype_vec_t` are now boxed vectors in the Wasmer C API + ## 1.0.0-beta2 - 2020-12-16 ### Added diff --git a/lib/c-api/src/wasm_c_api/macros.rs b/lib/c-api/src/wasm_c_api/macros.rs index f0225f3ddd2..cc5a520d2ec 100644 --- a/lib/c-api/src/wasm_c_api/macros.rs +++ b/lib/c-api/src/wasm_c_api/macros.rs @@ -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 [](out: *mut []) { // 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 [] { @@ -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 [](out: *mut [], length: usize, init: *mut []) { let mut bytes: Vec<[]> = 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 [](out: *mut [], length: usize) { let mut bytes: Vec<[]> = 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 [](ptr: Option<&mut []>) { 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 [] { @@ -153,6 +246,27 @@ macro_rules! wasm_declare_boxed_vec { } } + impl<'a, T: Into<[]> + Clone> From<&'a [T]> for [] { + 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::]>>() + .into_boxed_slice(); + let data = copied_data.as_mut_ptr(); + ::std::mem::forget(copied_data); + + Self { + size, + data, + } + } + } + // TODO: do this properly impl [] { pub unsafe fn into_slice(&self) -> Option<&[Box<[]>]>{ @@ -171,35 +285,71 @@ macro_rules! wasm_declare_boxed_vec { #[no_mangle] pub unsafe extern "C" fn [](out: *mut [], length: usize, init: *const *mut []) { let mut bytes: Vec<*mut []> = 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 [](out: *mut [], length: usize) { - let mut bytes: Vec<*mut []> = Vec::with_capacity(length); + let mut bytes: Vec<*mut []> = vec![::std::ptr::null_mut(); 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 [](ptr: *mut []) { - let vec = &mut *ptr; - if !vec.data.is_null() { - let data: Vec<*mut []> = Vec::from_raw_parts(vec.data, vec.size, vec.size); - let _data: Vec]>> = ::std::mem::transmute(data); - vec.data = ::std::ptr::null_mut(); - vec.size = 0; + pub unsafe extern "C" fn [](ptr: Option<&mut []>) { + if let Some(vec) = ptr { + if !vec.data.is_null() { + let data: Vec<*mut []> = Vec::from_raw_parts(vec.data, vec.size, vec.size); + let _data: Vec]>>> = ::std::mem::transmute(data); + + vec.data = ::std::ptr::null_mut(); + vec.size = 0; + } } } } @@ -222,7 +372,6 @@ macro_rules! wasm_declare_ref_base { } // TODO: finish this... - } }; } diff --git a/lib/c-api/src/wasm_c_api/types/frame.rs b/lib/c-api/src/wasm_c_api/types/frame.rs index d926ce977b9..99f3361ab63 100644 --- a/lib/c-api/src/wasm_c_api/types/frame.rs +++ b/lib/c-api/src/wasm_c_api/types/frame.rs @@ -48,4 +48,4 @@ pub unsafe extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t) -> usize frame.info.module_offset() } -wasm_declare_vec!(frame); +wasm_declare_boxed_vec!(frame); diff --git a/lib/c-api/src/wasm_c_api/types/function.rs b/lib/c-api/src/wasm_c_api/types/function.rs index 35b845481d6..a5318dbef45 100644 --- a/lib/c-api/src/wasm_c_api/types/function.rs +++ b/lib/c-api/src/wasm_c_api/types/function.rs @@ -1,7 +1,4 @@ -use super::{ - wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_delete, wasm_valtype_vec_t, WasmExternType, -}; -use std::mem; +use super::{wasm_externtype_t, wasm_valtype_vec_delete, wasm_valtype_vec_t, WasmExternType}; use wasmer::{ExternType, FunctionType, ValType}; #[derive(Debug)] @@ -13,44 +10,8 @@ pub(crate) struct WasmFunctionType { impl WasmFunctionType { pub(crate) fn new(function_type: FunctionType) -> Self { - let params = { - let mut valtypes = function_type - .params() - .iter() - .cloned() - .map(Into::into) - .map(Box::new) - .map(Box::into_raw) - .collect::>(); - - let valtypes_vec = Box::new(wasm_valtype_vec_t { - size: valtypes.len(), - data: valtypes.as_mut_ptr(), - }); - - mem::forget(valtypes); - - valtypes_vec - }; - let results = { - let mut valtypes = function_type - .results() - .iter() - .cloned() - .map(Into::into) - .map(Box::new) - .map(Box::into_raw) - .collect::>(); - - let valtypes_vec = Box::new(wasm_valtype_vec_t { - size: valtypes.len(), - data: valtypes.as_mut_ptr(), - }); - - mem::forget(valtypes); - - valtypes_vec - }; + let params: Box = Box::new(function_type.params().into()); + let results: Box = Box::new(function_type.results().into()); Self { function_type, @@ -90,12 +51,12 @@ impl wasm_functype_t { } } -wasm_declare_vec!(functype); +wasm_declare_boxed_vec!(functype); #[no_mangle] pub unsafe extern "C" fn wasm_functype_new( - params: Option>, - results: Option>, + params: Option<&mut wasm_valtype_vec_t>, + results: Option<&mut wasm_valtype_vec_t>, ) -> Option> { let params = params?; let results = results?; @@ -111,8 +72,8 @@ pub unsafe extern "C" fn wasm_functype_new( .map(|val| val.as_ref().into()) .collect::>(); - wasm_valtype_vec_delete(Box::into_raw(params)); - wasm_valtype_vec_delete(Box::into_raw(results)); + wasm_valtype_vec_delete(Some(params)); + wasm_valtype_vec_delete(Some(results)); Some(Box::new(wasm_functype_t::new(FunctionType::new( params_as_valtype, diff --git a/lib/c-api/src/wasm_c_api/types/global.rs b/lib/c-api/src/wasm_c_api/types/global.rs index 2195933334c..1b202ad8473 100644 --- a/lib/c-api/src/wasm_c_api/types/global.rs +++ b/lib/c-api/src/wasm_c_api/types/global.rs @@ -46,7 +46,7 @@ impl wasm_globaltype_t { } } -wasm_declare_vec!(globaltype); +wasm_declare_boxed_vec!(globaltype); #[no_mangle] pub unsafe extern "C" fn wasm_globaltype_new( diff --git a/lib/c-api/src/wasm_c_api/types/memory.rs b/lib/c-api/src/wasm_c_api/types/memory.rs index d38385b88e5..948ff6cf1ec 100644 --- a/lib/c-api/src/wasm_c_api/types/memory.rs +++ b/lib/c-api/src/wasm_c_api/types/memory.rs @@ -48,7 +48,7 @@ impl wasm_memorytype_t { } } -wasm_declare_vec!(memorytype); +wasm_declare_boxed_vec!(memorytype); #[no_mangle] pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box { diff --git a/lib/c-api/src/wasm_c_api/types/table.rs b/lib/c-api/src/wasm_c_api/types/table.rs index 31e2525eddd..1f30ad17981 100644 --- a/lib/c-api/src/wasm_c_api/types/table.rs +++ b/lib/c-api/src/wasm_c_api/types/table.rs @@ -53,7 +53,7 @@ impl wasm_tabletype_t { } } -wasm_declare_vec!(tabletype); +wasm_declare_boxed_vec!(tabletype); #[no_mangle] pub unsafe extern "C" fn wasm_tabletype_new(