-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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
os: GOOS=wasip1 returns non-IsNotExist errors on non-existent files #60732
Comments
CC @golang/wasm |
It seems to me that using
vs:
|
I believe this is working "as intended" based on the documentation in https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-tutorial.md#executing-in-wasmtime-runtime Like @cuonglm reported, It's possible that there is a better way to handle this runtime-specific behavior tho, "Bad file number" is difficult to interpret correctly as a user. At the same time, I would like to avoid making too many special cases in Go, especially because there is no convention to reliably detect which wasm runtime is in use from the guest side. Maybe we can try to align on the behavior of other compilers (e.g. TinyGo, Zig, Rust), so it's not "more broken" with Go. |
@achille-roussel I am facing a similar issue, PTAL if #63466 is intended behaviour or not. |
@HarikrishnanBalagopal, it appears the difference comes from TinyGo and Go possibly using different default working directories. Unfortunately, there is no concept of working directory in the wasip1 specification, so it's expected that different compilers will end up with diverging behaviors. Go interprets the |
@achille-roussel Setting the environment variable
The JS Code is as shown in the README https://github.com/bjorn3/browser_wasi_shim#usage const env = ["FOO=bar", "PWD=/", "MYPWD=/"];
......
const wasi = new WASI(args, env, fds); The Golang code is logrus.Infof("start 8!!")
logrus.Infof("just before Getwd, environment variable FOO is %s", os.Getenv("FOO"))
logrus.Infof("just before Getwd, environment variable PWD is %s", os.Getenv("PWD"))
logrus.Infof("just before Getwd, environment variable MYPWD is %s", os.Getenv("MYPWD"))
pwd, err := os.Getwd()
logrus.Infof("pwd: '%s'", pwd)
must(err)
fs, err := os.ReadDir(pwd)
must(err) Update:
Update 2: fs, err := os.ReadDir(".") This was working previously when we were not setting the
Update 3: const env = ["FOO=bar", "MYPWD=/"]; Then we get back to our previous failure at
Update 5: Another thing I noticed is the difference in output of TinyGo and Go when printing the file infos returned by fs, err := os.ReadDir(".")
must(err)
for _, f := range fs {
logrus.Infof("f: %+v", f)
} The Go compiler produces this output
while TinyGo actually prints the struct fields as expected of
The discrepancy seems to be because it's an interface Lines 86 to 106 in 8222423
|
This is working OK: # main.go
package main
import (
"os"
"github.com/sirupsen/logrus"
)
func must(err error) {
if err != nil {
panic(err)
}
}
func main() {
logrus.Infof("start v7!!")
fs, err := os.ReadDir("/")
must(err)
for _, f := range fs {
logrus.Infof("f: %+v", f)
}
b, err := os.ReadFile("/dep.json")
must(err)
logrus.Infof("The contents are:\n%s", string(b))
logrus.Infof("done")
}
I'm tempted to say it is due to a behavior difference between the WASI shim and those other WASI runtimes. Are you able to make it work with the WASI module of Node 20? |
@achille-roussel Nice! I also just got it to work by changing the JS code a bit Old code new PreopenDirectory(".", { New code new PreopenDirectory("/", {
The Go code package main
import (
"os"
"github.com/sirupsen/logrus"
)
func must(err error) {
if err != nil {
panic(err)
}
}
func main() {
logrus.Infof("start 13!!")
logrus.Infof("just before Getwd, environment variable FOO is %s", os.Getenv("FOO"))
logrus.Infof("just before Getwd, environment variable PWD is %s", os.Getenv("PWD"))
logrus.Infof("just before Getwd, environment variable MYPWD is %s", os.Getenv("MYPWD"))
pwd, err := os.Getwd()
logrus.Infof("pwd: '%s'", pwd)
must(err)
fs, err := os.ReadDir(".")
must(err)
for _, f := range fs {
logrus.Infof("f: %+v", f)
}
logrus.Infof("just before ReadFile, environment variable FOO is %s", os.Getenv("FOO"))
logrus.Infof("just before ReadFile, environment variable PWD is %s", os.Getenv("PWD"))
logrus.Infof("just before ReadFile, environment variable MYPWD is %s", os.Getenv("MYPWD"))
b, err := os.ReadFile("dep.json")
must(err)
logrus.Infof("The contents are:\n%s", string(b))
logrus.Infof("done")
} |
I notice significant difference between runtimes as well, Wasmer
Wasmtime
Wasmedge
Chrome browser with WASI FS shim JS library
Node 20 WASI
NodeJS code 'use strict';
const { readFile } = require('node:fs/promises');
const { WASI } = require('wasi');
const { argv, env } = require('node:process');
const { join } = require('node:path');
const wasi = new WASI({
version: 'preview1',
args: argv,
env,
preopens: {
'/': __dirname,
},
});
console.log('__dirname', __dirname);
(async () => {
const wasm = await WebAssembly.compile(
await readFile(join(__dirname, 'test.wasm')),
);
const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject());
wasi.start(instance);
})(); |
@HarikrishnanBalagopal based on your examples, I think the guidelines here are the following:
If you can contribute, having working examples of a simple program like yours demonstrating how to run on different runtimes would be a great addition to the wiki as well! |
I'm trying to run some code with to-be Go 1.21's wasip1/wasm support.
We have some code:
And instead of hitting that
os.IsNotExist
path, it's going into thecase err != nil
path with:It's possible I'm holding
wasmtime
wrong, but "Bad file number" doesn't tell me much. Is that a not found error or a sandbox violation error, or ...?/cc @johanbrandhorst
The text was updated successfully, but these errors were encountered: