jedisct1 / as-wasi Goto Github PK
View Code? Open in Web Editor NEWAn AssemblyScript API layer for WASI system calls.
License: MIT License
An AssemblyScript API layer for WASI system calls.
License: MIT License
Hello,
I'm trying to use as-wasi
but when trying Environ
it fails with
~lib/rt/tlsf.ts:457:29: error: allocation too large
Exception: wasi proc exit
I have tried several wasi-compliant runtimes but with the same result.
I'm using the latest master branch in package.json.
However using
"assemblyscript": "^0.8.1",
"as-wasi": "0.0.1"
it works.
Any suggestions, please?
Note well: this is a copy of bytecodealliance/wasmtime#2373, as requested here.
I've written a simple "echo" program using AssemblyScript and as-wasi. The program reads the user input from STDIN and writes it back to STDOUT.
Unfortunately it looks like I can never get back the input I enter.
This the source code of the AssemblyScript program I'm running:
import "wasi"
import {Console} from "as-wasi"
Console.log("type something");
let input: string | null;
let msg : string = "nothing";
input = Console.readAll();
if (input != null) {
msg = input!
}
Console.log('I got: ' + msg);
The program can be compiled to a WASM binary by doing:
$ asc echo.ts -b echo.wasm
And it can be run in this way:
$ wasmtime run echo.wasm
The program will start and I'll be able to enter my text. The program will keep reading from STDIN until I send the EOF
symbol (I'm on Linux -> CTRL-D
).
Unfortunately the input
variable is always null
.
I would expect the WASM program to be able to read data from stdin. The input
object should hold the text I entered on my terminal.
This is my stack:
as-wasi
: 0.4.0I'm running on a x86_64 Linux box that has openSUSE Tumbleweed
More information...
The as-wasi
handles STDIN/STDOUT/STDERR by using instances of the Descriptor class. The library simply opens the file descriptor 0
for STDIN, 1
for STDOUT and 2
for STDERR. In my tests it looks like opening the file descriptor 0
always returns a null
instance of Descriptor
; this doesn't happen with STDOUT and STDERR.
The same issue happens also when running the program through a custom made Go program I wrote leveraging wasmtime-go
.
In that case I even tried to start the WASM binary not by inheriting the parent STDIN, but instead by using a text file I previously created. Also in this case the WASM binary got a null
object when reading from the STDIN.
Relevant: a similar WASM binary, generated by translating Rust -> WASM, just works as expected.
Hello!
Was wondering if you were going to allow this to be npm-installable? π
It could be installed from the Github directly if we add a name
field to the package.json
.
Thanks! π
details:
wasm runtime: wasmer v0.4.2
assemblyscript version: v0.6
wasa version: master branch, commit f4162e73b6cbc3efd59f5cadd26b8b5b579b268f
// The entry file of your WebAssembly module.
import "allocator/arena"
import {
Console as console,
FileSystem as fs
} from '../wasa/assembly/wasa'
export function _start (): void {
let file = fs.open('./package.json')
let fileDetails = file.stat()
console.log(fileDetails.file_size.toString()) // always prints 0
console.log(fileDetails.file_type.toString()) // always prints 0
console.log(fileDetails.modification_time.toString()) // always prints 0.0
}
a few things come to mind...
or it could be something else! :)
Hello,
Is it possible to add API support for Descriptor to read and write binary strings (i.e., ArrayBuffer)? (If itβs there, I havenβt been able to find it.)
Thank you!
Hello!
I noticed that Date.now() returns the timestamp in microseconds instead of milliseconds.
This is a follow up of #95 - the reproducer is always the same, but I'm going to write it.
I've written a simple "echo" program using AssemblyScript and as-wasi. The program reads the user input from STDIN and writes it back to STDOUT.
Unfortunately the program crashes right after the EOF
symbol is received.
This the source code of the AssemblyScript program I'm running:
import "wasi"
import {Console} from "as-wasi"
Console.log("type something");
let input: string | null;
let msg : string = "nothing";
input = Console.readAll();
if (input != null) {
msg = input!
}
Console.log('I got: ' + msg);
The program can be compiled to a WASM binary by doing:
$ asc echo.ts -b echo.wasm
And it can be run in this way:
$ wasmtime run echo.wasm
The program starts and I can enter my text. The program keeps reading from STDIN until it gets the EOF
symbol (I'm on Linux -> CTRL-D
).
The program crashes as soon as the EOF
, this is the output I get:
type something
abort: in ~lib/rt/pure.ts(112:14)
Error: failed to run main module `stdin-test.wasm`
Caused by:
0: failed to invoke command default
1: exit with invalid exit status outside of [0..126)
wasm backtrace:
0: 0x555 - <unknown>!<wasm function 9>
1: 0x1f6 - <unknown>!<wasm function 3>
2: 0x209 - <unknown>!<wasm function 4>
3: 0x2490 - <unknown>!<wasm function 54>
4: 0x2584 - <unknown>!<wasm function 57>
5: 0x25d8 - <unknown>!<wasm function 58>
This can be triggered also in an automated fashion:
$ echo "hello" | wasmtime run echo.wasm
I would expect the WASM program to be able to read data from stdin. The input
object should hold the text I entered on my terminal.
This is my stack:
as-wasi
: 0.4.3I'm running on a x86_64 Linux box that has openSUSE Tumblewee
According to this comment from @peterhuene:
It looks like something is calling
proc_exit
with an exit code outside of the WASI-defined acceptable range of [0..126) (granted this range isn't part of the current WASI snapshot yet, so Wasmtime is being a little overzealous with this enforcement).
Using the Environ
class causes the program to crash with the following error:
Error: failed to run main module `env-test.wasm`
Caused by:
0: failed to instantiate "env-test.wasm"
1: unknown import: `env::abort` has not been defined
Use the example provided by the README of this project:
// Import from the installed as-wasi package
import { Console, Environ } from "as-wasi";
// Create an envrion instance
let env = new Environ();
// Get the HOME Environment variable
let home = env.get("HOME")!;
// Log the HOME string to stdout
Console.log(home);
Build the code and then execute it via wasmtime:
$ asc env-test.ts -b env-test.wasm
$ wasmtime run --env HOME=flavio env-test.wasm
Error: failed to run main module `env-test.wasm`
Caused by:
0: failed to instantiate "env-test.wasm"
1: unknown import: `env::abort` has not been defined
This is my stack:
Is there a way to pass data into stdin via wasi context?
When file already exist it will be truncated during wasi context creation
final var stdinPath = Paths.get("./wasm/io/stdin.txt");
Files.writeString(stdinPath, "{\"name\": \"John\"}");
final var wasi = new WasiCtxBuilder()
.stdin(stdinPath)
.build();
Another case, when trying to write data after context creation it is ignored
final var stdinPath = Paths.get("./wasm/io/stdin.txt");
final var wasi = new WasiCtxBuilder()
.stdin(stdinPath)
.build();
Files.writeString(stdinPath, "{\"name\": \"John\"}");
You can find full working example here: https://github.com/amysyk-viax-io/wasmtime-java-stdin-stdout
I see you've updated to use wasi-shim
, but it's not clear how usage/configuration has changed.
import "wasi"
, right?asconfig.json
?Adding nothing results in a module that won't execute:
Error: failed to run main module `build/debug.wasm`
Caused by:
0: failed to instantiate "build/debug.wasm"
1: unknown import: `env::abort` has not been defined
Following the instructions from wasi-shim
results in a module that won't compile.
ERROR TS2300: Duplicate identifier 'wasi_abort'.
:
1100 β export function wasi_abort(
β ~~~~~~~~~~
ββ in ~lib/as-wasi/assembly/as-wasi.ts(1100,17)
:
19 β export function wasi_abort(
β ~~~~~~~~~~
ββ in ~lib/wasi_internal.ts(19,17)
I'm using the following to load a multi-line file into a string array:
const fileOrNull: Descriptor | null = FileSystem.open(filename, "r");
if (fileOrNull == null) {
throw new Error("Could not open the file " + filename);
}
const file = changetype<Descriptor>(fileOrNull);
const lines = new Array<string>();
let line = changetype<string>(file.readLine());
do {
lines.push(line);
line = changetype<string>(file.readLine());
} while(line)
return lines;
However, give the following input:
one
two
three
The result is an array ["one", "two"]
- the readLine
method appears to return null prematurely
Just following the Quick Start:
// Import from the installed as-wasi package
import { Console, Environ } from "as-wasi/assembly";
// Create an environ instance
let env = new Environ();
// Get the HOME Environment variable
let home = env.get("HOME")!;
// Log the HOME string to stdout
Console.log(home);
Then building asc assembly/index.ts --target release
throws compile error:
ERROR TS2304: Cannot find name 'abort'.
:
935 β abort();
β ~~~~~
ββ in ~lib/as-wasi/assembly/as-wasi.ts(935,7)
ERROR TS2304: Cannot find name 'abort'.
:
944 β abort();
β ~~~~~
ββ in ~lib/as-wasi/assembly/as-wasi.ts(944,7)
FAILURE 2 compile error(s)
This error disappears if I don't useEnviron
but only Console
for example.
Maybe related to #127
Context: AssemblyScript/assemblyscript#1945
I guess the solution would be to add @unmanaged
and then we should be good to go here π
In the README it says to install by running npm install --save as-bind
instead of npm install --save as-wasi
, is this a mistake or am I missing something?
For example in: https://github.com/jedisct1/as-wasi/blob/master/assembly/as-wasi.ts#L281
I didn't realize I had the wrong permissions when opening a file, so when I tried to write to the file, it would silently fail. Perhaps we should think of a way to handle this? π
As far as I can tell, it is legal to have an environment variable like this:
QUERY_STRING=bar=baz
This is equivalent to QUERY_STRING="bar=baz"
.
However, if I try to access the above in as-wasi
's Envron
, I get only bar
.
import { Console, Environ } from "as-wasi";
let env = new Environ();
// export QUERY_STRING=bar=baz
let foo_env = env.get("QUERY_STRING")
let foo = foo_env === null ? "not set" : <string>foo_env;
Console.log("Value of QUERY_STRING: " + foo);
The problem seems to be that split("=", 2)
splits all of the =
, but then returns only the first 2 results (unlike similar functions in other languages that actually stop parsing once the limit is reached).
Bonjour,
Would you please make a new release, to solve compatibility with AssemblyScript via removal of wasi_abort()
?
Merci!
Hello! I've run a lot of a AssemblyScript Wasm modules while working on Wasmer's WASI implementation and noticed that AssemblyScript doesn't seem to do the same kind of filesystem setup work that Rust and C do in regards to preopened directories. This manifests as AssemblyScript Wasm modules behaving incorrectly (well, at least differently from Rust and C) when dealing with multiple preopened directories and in some cases with relative paths.
I have a lot of context on the WASI filesystem and would be happy to make a PR implementing that logic!
I haven't had a chance to take a good look at the code yet, but part of what we'll need is to execute logic in _start
, before main
, if we can't do that, then that's something else that we'll need to implement.
It looks like the primary thing to update is here. As part of this, I believe we'll need to do prefix search. I'll start with a linear string comparison based search which can be turned into iterative hashing and then a proper data structure like a prefix tree. Given the number of pre open directories in cases I've seen, linear search or iterative substring hashing (at the file component level) are probably the right trade off in terms of binary size vs speed here.
So it really should just come down to:
_start
dirfdForPath
(finding the right fd with the data structure from the step above)It's not really clear how to apply the bindings.json or which tool is used for this.
Just instantiating an Environ
object when environment variables are passed results in an error:
index.ts
:
import { Console, Environ } from "as-wasi";
export function _start(): void {
let env = new Environ();
// let all_vars = env.all();
// all_vars.forEach(function (val) {
// Console.log(val.key + "=" + val.value);
// });
}
package.json
:
"dependencies": {
"as-wasi": "^0.2.0",
"assemblyscript": "^0.14.0"
},
"scripts": {
"asbuild-test": "asc index.ts --use abort=wasi_abort --debug -b output/repro.wasm"
}
Trying to use the resulting module with Wasmtime results in an allocation error:
$ wasmtime output/repro.wasm --env foo=bar
~lib/rt/tlsf.ts:461:30: error: allocation too large
And the same happens with the WASI implementation in NodeJS (14.5):
"use strict";
const fs = require("fs");
const { WASI } = require("wasi");
const wasi = new WASI({
env: { foo: "bar" },
});
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
(async () => {
const wasm = await WebAssembly.compile(
fs.readFileSync("./output/repro.wasm")
);
const instance = await WebAssembly.instantiate(wasm, importObject);
wasi.start(instance);
})();
$ node --experimental-wasi-unstable-preview1 --experimental-wasm-bigint node_wasi.js
~lib/rt/tlsf.ts:461:30: error: allocation too large
It turns out reverting to version 0.0.1 of as-wasi
results in the complete example above working in both runtimes, and going through the changelist, @technosophos and I pinned this down to how StringUtils
works. Specifically, this particular change to the fromCString
method - passing the maximum integer value instead of the actual size of the string seems to be the one generating the error in allocation (the decodeUnsafe
method tries to allocate based on the actual size parameter, and I suspect this is where the overflow happens). Reverting just the fromCString
method to its previous version seems to fix the allocation issue.
Note that the same error occurs when trying to get command line arguments, since it is the only other place where fromCString
is used.
A quick fix for this would be reverting fromCString
's implementation to the version before that particular commit.
Hello!
Was wondering if you were going to give a license the project? π
Thanks!
are there any plans to implement fd_pread ?
I can not seem to open a regular file for reading. In this example, i call Filesystem.openForRead('./foo')
on a local file in the directory, but this method always returns 0
or the stdin file descriptor. am I using these methods as intended or am i missing something?
Thanks!
import "allocator/arena";
import { Console, IO, Filesystem } from "./wasa";
import { wasiabort } from './env'
// entrypoint for wasmer
export function _start(): void {
let fd = Filesystem.openForRead('./foo')
Console.log(fd.toString()) // prints '0'
let str = IO.readString(fd)
Console.log(str.slice(0, str.length - 1).split('').reverse().join(''))
}
The following reads a file line, by line, with the assumption that readLine
returns null
at the end of file:
index.ts:
import "wasi";
import { Console, FileSystem, Descriptor } from "as-wasi";
const filePath: string = "data.txt";
const fileOrNull: Descriptor | null = FileSystem.open(filePath, "r");
if (fileOrNull == null) {
throw new Error("Could not open the file " + filePath);
}
const file = changetype<Descriptor>(fileOrNull);
let line = changetype<string>(file.readLine());
while (line) {
Console.log(line);
line = changetype<string>(file.readLine());
}
package.json:
{
"scripts": {
"build": "asc assembly/index.ts -b build/index.wasm -t build/index.wat --runtime half",
"start": "wasmtime --dir . build/index.wasm",
"build:run": "npm run build && npm start"
},
"devDependencies": {
"assemblyscript": "0.17.3"
},
"dependencies": {
"as-wasi": "0.4.4"
}
}
However, readLine
never returns null.
I instead have to check for an empty line:
xlet line = changetype<string>(file.readLine());
while (line.length > 0) {
Console.log(line);
line = changetype<string>(file.readLine());
}
The Console.readAll function blocks until the EOF character is entered (e.g. by pressing CTRL-D in a linux shell), so it is not that useful for a CLI application.
It would be great if there was a function which reads a whole line until a newline character is entered (e.g. Console.readLine).
For portability this should probably take different newline character sequences into account (e.g. CR+LF for Windows and only LF for Linux/macOS).
How to use console (eg Console.readAll) without import "wasi"
, which is no longer supported?
https://github.com/AssemblyScript/wasi-shim#usage
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.