feat(c-api) Handle initialized but empty results in wasm_func_call.

Our implementation of `wasm_func_call` was correct for C code as
follows:

```c
wasm_val_vec_t arguments = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
wasm_func_call(func, &arguments, &results);
```

However, for a C code such as:

```c
wasm_val_t vals[1];
wasm_val_vec_t arguments = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_ARRAY_VEC(vals);
wasm_func_call(func, &arguments, &results);
```

the `vals` array were kept empty/unchanged. Why?

Because `wasm_func_call` was replacing the value of `results` by a new
`wasm_val_vec_t`. It is correct when `results` is an empty vector, but
it is incorrect when `results` is initialized with empty values.

This patch tries to detect this pattern: If `results.data` is `null`,
it means the vector is empty/uninitialized, and we can set a new
`wasm_val_vec_t`, otherwise it means the vector is initialized with
empty values, and we need to update each item individually.
This commit is contained in:
Ivan Enderlin
2020-10-30 13:30:14 +01:00
parent 92e4cf64c1
commit 758bc9bb78

View File

@@ -154,18 +154,34 @@ pub unsafe extern "C" fn wasm_func_call(
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.expect("Argument conversion failed")
.expect("Arguments conversion failed")
})
.unwrap_or_default();
match func.inner.call(&params) {
Ok(wasm_results) => {
*results = wasm_results
let vals = wasm_results
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed")
.into();
.expect("Results conversion failed");
// `results` is an uninitialized vector. Set a new value.
if results.size == 0 || results.data.is_null() {
*results = vals.into();
}
// `results` is an initialized but empty vector. Fill it
// item per item.
else {
let slice = results
.into_slice_mut()
.expect("`wasm_func_call`, results' size is greater than 0 but data is NULL");
for (result, value) in slice.iter_mut().zip(vals.iter()) {
(*result).kind = value.kind;
(*result).of = value.of;
}
}
None
}