Skip to content
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

fix(c-api) Don't drain the entire captured stream at first read #2070

Merged
merged 4 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- [#2056](https://github.com/wasmerio/wasmer/pull/2056) Change back to depend on the `enumset` crate instead of `wasmer_enumset`

### Fixed
- [#2070](https://github.com/wasmerio/wasmer/pull/2070) Do not drain the entire captured stream at first read with `wasi_env_read_stdout` or `_stderr` in the C API.
- [#2058](https://github.com/wasmerio/wasmer/pull/2058) Expose WASI versions to C correctly.
- [#2044](https://github.com/wasmerio/wasmer/pull/2044) Do not build C headers on docs.rs.

Expand Down
13 changes: 9 additions & 4 deletions lib/c-api/src/wasm_c_api/wasi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use super::{
// required due to really weird Rust resolution rules for macros
// https://github.com/rust-lang/rust/issues/57966
use crate::error::{update_last_error, CApiError};
use std::cmp::min;
use std::convert::TryFrom;
use std::ffi::CStr;
use std::os::raw::c_char;
Expand Down Expand Up @@ -275,12 +276,16 @@ pub unsafe extern "C" fn wasi_env_read_stderr(

fn read_inner(wasi_file: &mut Box<dyn WasiFile>, inner_buffer: &mut [u8]) -> isize {
if let Some(oc) = wasi_file.downcast_mut::<capture_files::OutputCapturer>() {
let mut num_bytes_written = 0;
for (address, value) in inner_buffer.iter_mut().zip(oc.buffer.drain(..)) {
let total_to_read = min(inner_buffer.len(), oc.buffer.len());

for (address, value) in inner_buffer
.iter_mut()
.zip(oc.buffer.drain(..total_to_read))
{
*address = value;
num_bytes_written += 1;
}
num_bytes_written

total_to_read as isize
} else {
-1
}
Expand Down
38 changes: 29 additions & 9 deletions lib/c-api/tests/test-wasi.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ int main(int argc, const char* argv[]) {
const char* js_string = "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));";
wasi_config_arg(config, "--eval");
wasi_config_arg(config, js_string);
wasi_config_capture_stdout(config);

wasi_env_t* wasi_env = wasi_env_new(config);
if (!wasi_env) {
Expand Down Expand Up @@ -125,16 +126,35 @@ int main(int argc, const char* argv[]) {
return 1;
}

char buffer[BUF_SIZE] = { 0 };
size_t result = BUF_SIZE;
for (size_t i = 0;
// TODO: this code is too clever, make the control flow more obvious here
result == BUF_SIZE &&
(result = wasi_env_read_stdout(wasi_env, buffer, BUF_SIZE));
++i) {
printf("%.*s", BUF_SIZE, buffer);
{
FILE *memory_stream;
char* stdout;
size_t stdout_size = 0;

memory_stream = open_memstream(&stdout, &stdout_size);

if (NULL == memory_stream) {
printf("> Error creating a memory stream.\n");
return 1;
}

char buffer[BUF_SIZE] = { 0 };
size_t data_read_size = BUF_SIZE;

do {
data_read_size = wasi_env_read_stdout(wasi_env, buffer, BUF_SIZE);

if (data_read_size > 0) {
stdout_size += data_read_size;
fwrite(buffer, sizeof(char), data_read_size, memory_stream);
}
} while (BUF_SIZE == data_read_size);

fclose(memory_stream);

printf("WASI Stdout: `%.*s`\n", (int) stdout_size, stdout);
}
printf("\n");


wasm_extern_vec_delete(&exports);
wasm_extern_vec_delete(&imports);
Expand Down