diff --git a/test-all.sh b/test-all.sh index 2bb944cc6c..5f7a1be06a 100755 --- a/test-all.sh +++ b/test-all.sh @@ -45,7 +45,7 @@ cargo build # Run the tests. We run these in debug mode so that assertions are enabled. banner "Rust unit tests" -RUST_BACKTRACE=1 cargo test +RUST_BACKTRACE=1 cargo test --all # Make sure the documentation builds. banner "Rust documentation: $topdir/target/doc/wasi-common/index.html" diff --git a/wasi-common-cbindgen/src/lib.rs b/wasi-common-cbindgen/src/lib.rs index 0eab409f61..c8d780b285 100644 --- a/wasi-common-cbindgen/src/lib.rs +++ b/wasi-common-cbindgen/src/lib.rs @@ -2,7 +2,7 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::{ArgCaptured, FnArg, Pat, PatIdent, Type, TypeReference}; +use syn::{ArgCaptured, FnArg, Pat, PatIdent, Type, TypeReference, TypeSlice}; #[proc_macro_attribute] pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenStream { @@ -36,11 +36,31 @@ pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenSt if let Type::Reference(ty @ TypeReference { .. }) = &ty { // if we're here, then we found a &-ref // so substitute it for *mut since we're exporting to C - let elem = &ty.elem; - arg_type.push(quote!(*mut #elem)); - // we need to properly dereference the substituted raw - // pointer if we are to properly call the hostcall fn - call_arg_ident.push(quote!(&mut *#ident)); + let elem = &*ty.elem; + if let Type::Slice(elem @ TypeSlice { .. }) = &elem { + // slice: &[type] or &mut [type] + // in C it requires a signature *mut type + let elem = &elem.elem; + arg_type.push(quote!(*mut #elem)); + // since it's a slice, we'll need to do more work here + // simple dereferencing is not enough + // firstly, we need to add a len arg to C fn + // secondly, we need to invoke std::slice::from_raw_parts_mut(..) + let concatenated = format!("{}_len", ident); + let len_ident = syn::Ident::new(&concatenated, ident.span()); + call_arg_ident.push(quote! { + std::slice::from_raw_parts_mut(#ident, #len_ident) + }); + arg_ident.push(quote!(#len_ident)); + arg_type.push(quote!(usize)); + } else { + // & or &mut type + // so simply substitute with *mut type + arg_type.push(quote!(*mut #elem)); + // we need to properly dereference the substituted raw + // pointer if we are to properly call the hostcall fn + call_arg_ident.push(quote!(&mut *#ident)); + } } else { arg_type.push(quote!(#ty)); // non-&-ref type, so preserve whatever the arg was diff --git a/wasi-common-cbindgen/tests/array_args.rs b/wasi-common-cbindgen/tests/array_args.rs new file mode 100644 index 0000000000..fa93d1b91f --- /dev/null +++ b/wasi-common-cbindgen/tests/array_args.rs @@ -0,0 +1,20 @@ +extern crate wasi_common_cbindgen; + +pub use wasi_common_cbindgen::wasi_common_cbindgen; + +#[wasi_common_cbindgen] +fn array_args(a: &mut [u8]) { + a[0] = 1; +} + +fn main() { + let mut expected: &mut [u8] = &mut [0, 0]; + array_args(&mut expected); + + let given: &mut [u8] = &mut [0, 0]; + unsafe { + __wasi_array_args(given.as_mut_ptr(), given.len()); + } + + assert_eq!(given, expected); +} diff --git a/wasi-common-cbindgen/tests/mut_args.rs b/wasi-common-cbindgen/tests/mut_args.rs index 036f8d86cc..7bce5ccbc6 100644 --- a/wasi-common-cbindgen/tests/mut_args.rs +++ b/wasi-common-cbindgen/tests/mut_args.rs @@ -17,4 +17,4 @@ fn main() { Box::from_raw(raw) }; assert_eq!(*given, *expected); -} \ No newline at end of file +} diff --git a/wasi-common-cbindgen/tests/ref_args.rs b/wasi-common-cbindgen/tests/ref_args.rs index 72aea6e9d3..57c988241f 100644 --- a/wasi-common-cbindgen/tests/ref_args.rs +++ b/wasi-common-cbindgen/tests/ref_args.rs @@ -17,4 +17,4 @@ fn main() { res }; assert_eq!(given, expected); -} \ No newline at end of file +} diff --git a/wasi-common-cbindgen/tests/test.rs b/wasi-common-cbindgen/tests/test.rs index 9868f9c543..678e1f4dac 100644 --- a/wasi-common-cbindgen/tests/test.rs +++ b/wasi-common-cbindgen/tests/test.rs @@ -5,4 +5,5 @@ fn tests() { t.pass("tests/val_args.rs"); t.pass("tests/ref_args.rs"); t.pass("tests/mut_args.rs"); -} \ No newline at end of file + t.pass("tests/array_args.rs"); +} diff --git a/wasi-common-cbindgen/tests/val_args.rs b/wasi-common-cbindgen/tests/val_args.rs index e90509b0de..68b6d27eef 100644 --- a/wasi-common-cbindgen/tests/val_args.rs +++ b/wasi-common-cbindgen/tests/val_args.rs @@ -9,4 +9,4 @@ fn val_args(a: usize, b: usize) -> usize { fn main() { assert_eq!(unsafe { __wasi_val_args(1, 2) }, val_args(1, 2)); -} \ No newline at end of file +}