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

Please tell me how to properly handle stdio #2178

Closed
goccy opened this issue Apr 8, 2024 · 3 comments
Closed

Please tell me how to properly handle stdio #2178

goccy opened this issue Apr 8, 2024 · 3 comments
Labels
question Further information is requested

Comments

@goccy
Copy link

goccy commented Apr 8, 2024

Describe the bug

I'm developing a plugin using wazero and I'm trying to use stdio to exchange data between host and plugin.
However, I noticed that the behavior of Read was different from that of a normal Go program.
Normally, Read blocks until calling Write syscall, but when I run the plugin using wazero, it always seems to receive io.EOF .

Similarly, when I call Write API for os.Stdout on the plugin side, it could not be Read properly on the host side.

To Reproduce

I prepared example repository to reproduce this issue.

https://github.com/goccy/wazero-example

Plugin code is here.

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	for {
		content, err := reader.ReadString('\n')
		fmt.Fprintf(os.Stderr, "content = %s. err = %v\n", content, err)
	}
}

Host code is here

package main

import (
	"bytes"
	"context"
	_ "embed"
	"fmt"
	"os"

	"github.com/tetratelabs/wazero"
	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)

//go:embed plugin.wasm
var wasmFile []byte

func main() {
	ctx := context.Background()
	cfg := wazero.NewRuntimeConfig()
	r := wazero.NewRuntimeWithConfig(ctx, cfg)

	builder := r.NewHostModuleBuilder("env")
	wasi_snapshot_preview1.NewFunctionExporter().ExportFunctions(builder)
	if _, err := builder.Instantiate(ctx); err != nil {
		panic(err)
	}

	wasi_snapshot_preview1.MustInstantiate(ctx, r)

	mod, err := r.CompileModule(ctx, wasmFile)
	if err != nil {
		panic(err)
	}
	stdin := bytes.NewBuffer([]byte{})
	stdout := bytes.NewBuffer([]byte{})
	modCfg := wazero.NewModuleConfig().
		WithStdin(stdin).
		WithStdout(stdout).
		WithStderr(os.Stderr)

	if _, err := r.InstantiateModule(ctx, mod, modCfg); err != nil {
		panic(err)
	}

	fmt.Fprintf(os.Stderr, "write buffer\n")
	if _, err := stdin.Write([]byte("hello world\n")); err != nil {
		panic(err)
	}
}

Expected behavior

I expect the plugin's fmt.Fprintf to be called only once, but in fact it is called constantly.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment (please complete the relevant information):

  • Go version: 1.21.0
  • wazero Version: v1.7.0
  • Host architecture: Darwin mc-XJK92G53P9 23.3.0 Darwin Kernel Version 23.3.0: Wed Dec 20 21:30:44 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6000 arm64
  • Runtime mode: compiler

Additional context
Add any other context about the problem here.

@goccy goccy added the bug Something isn't working label Apr 8, 2024
@mathetake mathetake added question Further information is requested and removed bug Something isn't working labels Apr 8, 2024
@evacchi
Copy link
Contributor

evacchi commented Apr 8, 2024

I think that's because you are plugging stdin to a buffer. If you need blocking behavior you can plug os.Stdin, or os.Pipe (io.Pipe might also work)

@goccy
Copy link
Author

goccy commented Apr 8, 2024

@evacchi Thank you for your advice !! I've fixed my example according to your advice, as a result, It's working correctly !

@mathetake
Copy link
Member

glad it's resolved!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants