Correctly unpack &mut [T] into *mut T and usize
This commit is contained in:
@@ -45,7 +45,7 @@ cargo build
|
|||||||
|
|
||||||
# Run the tests. We run these in debug mode so that assertions are enabled.
|
# Run the tests. We run these in debug mode so that assertions are enabled.
|
||||||
banner "Rust unit tests"
|
banner "Rust unit tests"
|
||||||
RUST_BACKTRACE=1 cargo test
|
RUST_BACKTRACE=1 cargo test --all
|
||||||
|
|
||||||
# Make sure the documentation builds.
|
# Make sure the documentation builds.
|
||||||
banner "Rust documentation: $topdir/target/doc/wasi-common/index.html"
|
banner "Rust documentation: $topdir/target/doc/wasi-common/index.html"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ extern crate proc_macro;
|
|||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{ArgCaptured, FnArg, Pat, PatIdent, Type, TypeReference};
|
use syn::{ArgCaptured, FnArg, Pat, PatIdent, Type, TypeReference, TypeSlice};
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenStream {
|
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 let Type::Reference(ty @ TypeReference { .. }) = &ty {
|
||||||
// if we're here, then we found a &-ref
|
// if we're here, then we found a &-ref
|
||||||
// so substitute it for *mut since we're exporting to C
|
// so substitute it for *mut since we're exporting to C
|
||||||
let elem = &ty.elem;
|
let elem = &*ty.elem;
|
||||||
arg_type.push(quote!(*mut #elem));
|
if let Type::Slice(elem @ TypeSlice { .. }) = &elem {
|
||||||
// we need to properly dereference the substituted raw
|
// slice: &[type] or &mut [type]
|
||||||
// pointer if we are to properly call the hostcall fn
|
// in C it requires a signature *mut type
|
||||||
call_arg_ident.push(quote!(&mut *#ident));
|
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 {
|
} else {
|
||||||
arg_type.push(quote!(#ty));
|
arg_type.push(quote!(#ty));
|
||||||
// non-&-ref type, so preserve whatever the arg was
|
// non-&-ref type, so preserve whatever the arg was
|
||||||
|
|||||||
20
wasi-common-cbindgen/tests/array_args.rs
Normal file
20
wasi-common-cbindgen/tests/array_args.rs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
@@ -5,4 +5,5 @@ fn tests() {
|
|||||||
t.pass("tests/val_args.rs");
|
t.pass("tests/val_args.rs");
|
||||||
t.pass("tests/ref_args.rs");
|
t.pass("tests/ref_args.rs");
|
||||||
t.pass("tests/mut_args.rs");
|
t.pass("tests/mut_args.rs");
|
||||||
|
t.pass("tests/array_args.rs");
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user