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

Output is different when connected to a shell vs a pipe #7833

Closed
aykevl opened this issue Jan 27, 2024 · 6 comments
Closed

Output is different when connected to a shell vs a pipe #7833

aykevl opened this issue Jan 27, 2024 · 6 comments
Labels
bug Incorrect behavior in the current implementation that needs fixing

Comments

@aykevl
Copy link

aykevl commented Jan 27, 2024

wasmtime has a different output depending on whether it is run normally or through a pipe (for example, tail).

Test Case

See the wasm.test file here:
wasm-test.zip

Steps to Reproduce

Normal case:

$ wasmtime run test.wasm
line written using C puts
hello world!

Output is redirected to a pipe:

$ wasmtime run test.wasm | tail
line written using C puts

For comparison, I tested the same thing in wasmer and it has the correct (first) output in both cases.

Expected Results

Output should be the same, regardless of where stdout is redirected.

Actual Results

The last line is somehow lost when stdout is redirected to a pipe (in this case, passing it to tail but I've also seen this issue when running from inside Go os/exec).

Versions and Environment

Wasmtime version or commit: wasmtime-cli 17.0.0

Operating system: Linux (Fedora Asahi)

Architecture: aarch64

Extra Info

This is a relatively big test case, I can try to make it smaller if needed.
For example, I've found it reproducible using fwrite("test\n", 5, 1, stdout);.

@aykevl aykevl added the bug Incorrect behavior in the current implementation that needs fixing label Jan 27, 2024
@alexcrichton
Copy link
Member

Thanks for the report! I can reproduce this behavior as well with the uploaded wasm. That being said though I'm not certian that this is a bug in Wasmtime. Through WASMTIME_LOG=trace in the non-piped case (tty stdout) the module is calling fd_write more times than in the piped case. In other words, in the piped case, the module itself isn't even requesting a print. The main difference here is that the module calls fd_fdstat_get and the tty version returns fs_filetype: CharacterDevice while the piped version returns fs_filetype: Unknown meaning that the module may use this to act differently.

Would you be able to share the source code of this module? The bug may be in TinyGo's standard library, but it might also be in wasi-libc. This may also be a bug that's since been fixed in wasi-libc and may require a newer build than you might be using. Hard to tell! If you're able to share the original source we can try to help dig in further.

Furthermore you mention fwrite("test\n", 5, 1, stdout); reproduces this behavior for you. Locally however I do not see a reproduction with a simple program doing that. This may indicate that this was a bug in wasi-libc that's since been fixed. Could you share the full source of the program (perhaps the module too) with fwrite and the version of wasi-sdk that you're using?

@aykevl
Copy link
Author

aykevl commented Feb 15, 2024

That being said though I'm not certian that this is a bug in Wasmtime.

Yeah, since reporting this bug I started to realize it's more likely to be a bug in wasm-libc.

The main difference here is that the module calls fd_fdstat_get and the tty version returns fs_filetype: CharacterDevice while the piped version returns fs_filetype: Unknown meaning that the module may use this to act differently.

Thanks! I wasn't aware that WASI allowed inspecting the output file type.

Would you be able to share the source code of this module?

It's essentially just testdata/cgo in https://github.com/tinygo-org/tinygo/pull/4101/files but without the fflush workaround.
Unfortunately, when I tried to reproduce it today I couldn't get it to fail. I don't remember updating anything (like wasmtime) so not sure why this is the case. Closing, I'll reopen the issue once I manage to reproduce it again.

@aykevl aykevl closed this as not planned Won't fix, can't repro, duplicate, stale Feb 15, 2024
@aykevl
Copy link
Author

aykevl commented Feb 15, 2024

Nevermind, that was a silly mistake on my side.

I can reproduce it using the following steps (this assumes you already have a working TinyGo build):

  1. Check out the cgo-printf branch of TinyGo.
  2. run go install, tinygo clean
  3. Comment out the fflush call at the bottom of testdata/cgo/main.c. (You can also uncomment most of the main function in testdata/cgo/main.go if you'd like).
  4. Build a binary using tinygo build -o test.wasm -target=wasi ./testdata/cgo
  5. Run it using wasmtime run test.wasm | tail.

That's rather involved just to reproduce this issue, I can try to make a reproducer that doesn't use TinyGo.

@aykevl aykevl reopened this Feb 15, 2024
@aykevl
Copy link
Author

aykevl commented Feb 15, 2024

This may also be a bug that's since been fixed in wasi-libc and may require a newer build than you might be using.

Tried again with the main branch of wasi-libc, same issue. So whatever it is, it doesn't look like it's fixed there.

@aykevl
Copy link
Author

aykevl commented Feb 15, 2024

Update: I can't seem to reproduce this with a simple 'hello world' in C, this needs a bit more investigation.

@aykevl
Copy link
Author

aykevl commented Feb 15, 2024

Ok, figured it out. I need to call __wasm_call_dtors before exiting. Apparently it flushes the stdout buffer.

See:
https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/crt/crt1-command.c#L46

@aykevl aykevl closed this as completed Feb 15, 2024
aykevl added a commit to tinygo-org/tinygo that referenced this issue Feb 16, 2024
This flushes stdio, so that functions like puts and printf write out all
buffered data even if the output isn't connected to a terminal.

For discussion, see:
bytecodealliance/wasmtime#7833
aykevl added a commit to tinygo-org/tinygo that referenced this issue Jun 24, 2024
This flushes stdio, so that functions like puts and printf write out all
buffered data even if the output isn't connected to a terminal.

For discussion, see:
bytecodealliance/wasmtime#7833
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Incorrect behavior in the current implementation that needs fixing
Projects
None yet
Development

No branches or pull requests

2 participants