WASI prototype design, implementation, and documentation.
This adds documents describing the WASI Core API, and an implementation in Wasmtime.
This commit is contained in:
@@ -31,6 +31,7 @@ wasmtime-runtime = { path = "wasmtime-runtime" }
|
||||
wasmtime-jit = { path = "wasmtime-jit" }
|
||||
wasmtime-obj = { path = "wasmtime-obj" }
|
||||
wasmtime-wast = { path = "wasmtime-wast" }
|
||||
wasmtime-wasi = { path = "wasmtime-wasi" }
|
||||
docopt = "1.0.1"
|
||||
serde = "1.0.75"
|
||||
serde_derive = "1.0.75"
|
||||
@@ -39,5 +40,7 @@ target-lexicon = { version = "0.3.0", default-features = false }
|
||||
pretty_env_logger = "0.3.0"
|
||||
file-per-thread-logger = "0.1.1"
|
||||
wabt = "0.7"
|
||||
libc = "0.2.50"
|
||||
errno = "0.2.4"
|
||||
|
||||
[workspace]
|
||||
|
||||
29
README.md
29
README.md
@@ -14,26 +14,27 @@ utility or as a library embedded in a larger application.
|
||||
[](https://gitter.im/CraneStation/Lobby)
|
||||

|
||||
|
||||
*Wasmtime is complete enough to pass the WebAssembly spec testsuite.* Support for
|
||||
system APIs is coming soon!
|
||||
Wasmtime passes the WebAssembly spec testsuite, and supports a new system
|
||||
API proposal called [WebAssembly System Interface], or WASI.
|
||||
|
||||
One goal for this project is to implement [CloudABI](https://cloudabi.org/) using
|
||||
WebAssembly as the code format, provide [CloudABI system calls] as WebAssembly
|
||||
host imports, and then port the [Rust CloudABI package] and [CloudABI libc] to it
|
||||
to support Rust, C, C++, and other toolchains.
|
||||
There are Rust C, and C++ toolchains that can compile programs with WASI. See
|
||||
[here][WASI intro] for more information, and [here][WASI tutorial] for a
|
||||
tutorial on compiling and running programs using WASI and wasmtime, as
|
||||
well as an overview of the filesystem sandboxing system.
|
||||
|
||||
CloudABI is a natural complement for WebAssembly, since WebAssembly provides
|
||||
sandboxing for code but doesn't have any builtin I/O, and CloudABI provides
|
||||
sandboxed I/O.
|
||||
Wasmtime does not yet implement Spectre mitiations, such as those being
|
||||
pioneered [by](https://www.wasmjit.org/blog/spectre-mitigations-part-1.html)
|
||||
[wasmjit](https://www.wasmjit.org/blog/spectre-mitigations-part-2.html),
|
||||
however this is a subject of ongoing research.
|
||||
|
||||
[CloudABI]: https://cloudabi.org/
|
||||
[CloudABI system calls]: https://github.com/NuxiNL/cloudabi#specification-of-the-abi
|
||||
[Rust CloudABI package]: https://crates.io/crates/cloudabi
|
||||
[CloudABI libc]: https://github.com/NuxiNL/cloudlibc
|
||||
[WebAssembly System Interface]: docs/WASI-overview.md
|
||||
[WASI intro]: docs/WASI-intro.md
|
||||
[WASI tutorial]: docs/WASI-tutorial.md
|
||||
|
||||
Additional goals for Wasmtime include:
|
||||
- Support a variety of host APIs (not just CloudABI), with fast calling sequences,
|
||||
and develop proposals for system calls in the WebAssembly
|
||||
- Support a variety of host APIs (not just WASI Core), with fast calling sequences,
|
||||
and develop proposals for additional API modules to be part of WASI.
|
||||
[Reference Sysroot](https://github.com/WebAssembly/reference-sysroot).
|
||||
- Implement the [proposed WebAssembly C API].
|
||||
- Facilitate testing, experimentation, and development around the [Cranelift] and
|
||||
|
||||
2305
docs/WASI-api.md
Normal file
2305
docs/WASI-api.md
Normal file
File diff suppressed because it is too large
Load Diff
179
docs/WASI-background.md
Normal file
179
docs/WASI-background.md
Normal file
@@ -0,0 +1,179 @@
|
||||
One of the biggest challenges in WebAssembly is figuring out what it's
|
||||
supposed to be.
|
||||
|
||||
## A brief tangent on some related history
|
||||
|
||||
The LLVM WebAssembly backend has gone down countless paths that it has
|
||||
ended up abandoning. One of the early questions was whether we should use
|
||||
an existing object file format, such as ELF, or design a new format.
|
||||
|
||||
Using an existing format is very appealing. We'd be able to use existing
|
||||
tools, and be familiar to developers. It would even make porting some
|
||||
kinds of applications easier. And existing formats carry with them
|
||||
decades of "lessons learned" from many people in many settings, building,
|
||||
running, and porting real-world applications.
|
||||
|
||||
The actual WebAssembly format that gets handed to platforms to run is
|
||||
its own format, but there'd be ways to make things work. To reuse existing
|
||||
linkers, we could have a post-processing tool which translates from the
|
||||
linker's existing output format into a runnable WebAssembly module. We
|
||||
actually made a fair amount of progress toward building this.
|
||||
|
||||
But then, using ELF for example, we'd need to create a custom segment
|
||||
type (in the `PT_LOPROC`-`PT_HIPROC` range) instead of the standard
|
||||
`PT_LOAD` for loading code, because WebAssembly functions aren't actually
|
||||
loaded into the program address space. And same for the `PT_LOAD` for the
|
||||
data too, because especially once WebAssembly supports threads, memory
|
||||
initialization will need to
|
||||
[work differently](https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#design).
|
||||
And we could omit the `PT_GNU_STACK`, because WebAssembly's stack can't
|
||||
be executable. And maybe we could omit `PT_PHDR` because unless
|
||||
we replicate the segment headers in data, they won't actually be
|
||||
accessible in memory. And so on.
|
||||
|
||||
And while in theory everything can be done within the nominal ELF
|
||||
standard, in practice we'd have to make major changes to existing ELF
|
||||
tools to support this way of using ELF, which would defeat many of the
|
||||
advantages we were hoping to get. And we'd still be stuck with a custom
|
||||
post-processing step. And it'd be harder to optimize the system to
|
||||
take advantage of the unique features of WebAssembly, because everything
|
||||
would have to work within this external set of constraints.
|
||||
|
||||
So while the LLVM WebAssembly backend started out trying to use ELF, we
|
||||
eventually decided to back out of that and design a
|
||||
[new format](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md).
|
||||
|
||||
## Now let's talk APIs
|
||||
|
||||
It's apparent to anyone who's looked under the covers at Emscripten's interface
|
||||
between WebAssembly and the outside world that the current system is particular
|
||||
to the way Emscripten currently works, and not well suited for broader adoption.
|
||||
This is especially true as interest grows in running WebAssembly outside
|
||||
of browsers and outside of JS VMs.
|
||||
|
||||
It's been obvious since WebAssembly was just getting started that it'd eventually
|
||||
want some kind of "system call"-like API, which could be standardized, and
|
||||
implemented in any general-purpose WebAssembly VM.
|
||||
|
||||
And while there are many existing systems we could model this after, [POSIX]
|
||||
stands out, as being a vendor-neutral standard with considerable momentum. Many
|
||||
people, including us, have been assuming that WebAssembly would eventually
|
||||
have some kind of POSIX API. Some people have even started experimenting with
|
||||
what
|
||||
[this](https://github.com/WAVM/Wavix/)
|
||||
[might](https://github.com/jfbastien/musl)
|
||||
[look](https://github.com/golang/go/blob/e5489cfc12a99f25331831055a79750bfa227943/misc/wasm/wasm_exec.js)
|
||||
[like](https://github.com/emscripten-core/emscripten/blob/incoming/src/library_syscall.js).
|
||||
|
||||
But while a lot of things map fairly well, some things are less clear. One of
|
||||
the big questions is how to deal with the concept of a "process". POSIX's IPC
|
||||
mechanisms are designed around process, and in fact, the term "IPC" itself
|
||||
has "process" baked into it. The way we even think about what "IPC" means
|
||||
bakes in in understandings about what processes are and what communication
|
||||
between them looks like.
|
||||
|
||||
Pipes, Unix-domain sockets, POSIX shared memory, signals, files with `fcntl`
|
||||
`F_SETLK`/`F_GETLK`-style locking (which is process-associated), are are tied
|
||||
to processes. But what *is* a process, when we're talking about WebAssembly?
|
||||
|
||||
## Stick a fork in it
|
||||
|
||||
Suppose we say that a WebAssembly instance is a "process", for the purposes
|
||||
of the POSIX API. This initially seems to work out well, but it leaves us
|
||||
with several holes to fill. Foremost is `fork`. `fork` is one of the pillars
|
||||
of Unix, but it's difficult to implement outside of a full Unix-style OS. We
|
||||
probably *can* make it work in all the places we want to run WebAssembly, but
|
||||
do we want to? It'd add a bunch of complexity, inefficiency, subtle behavioral
|
||||
differences, or realistically, a combination of all three.
|
||||
|
||||
Ok, so maybe we can encourage applications to use `posix_spawn` instead. And
|
||||
some already do, but in doing so we do loose some of the value of POSIX's
|
||||
momentum. And even with `posix_spawn`, many applications will explicitly do
|
||||
things like `waidpid` on the resulting PID. We can make this work too, but
|
||||
we should also take a moment and step back to think about IPC in general.
|
||||
|
||||
In WebAssembly, instances can synchronously call each other, and it can be
|
||||
very efficient. This is not something that typical processes can do. Arguably,
|
||||
a lot of what we now think of as "IPC" is just working around the inability
|
||||
of processes to have calls between each other. And, WebAssembly instances will
|
||||
be able to import each others' memories and tables, and eventually even pass
|
||||
around slices to their memories. In WebAssembly circles we don't even tend to
|
||||
think of these as IPC mechanisms, because the process metaphor just doesn't
|
||||
fit very well here. We're going to want applications to use these mechanisms,
|
||||
because they're efficient and take advantage of the platform, rather than
|
||||
using traditional Unix-style IPC which will often entail emulation and
|
||||
inefficiencies.
|
||||
|
||||
Of course, there will always be a role for aiding porting of existing
|
||||
applications. Libraries that emulate various details of Unix semantics are
|
||||
valuable. But we can consider them tools for solving certain practical
|
||||
problems, rather than the primary interfaces of the system, because they
|
||||
miss out on some of the platform's fundamental features.
|
||||
|
||||
## Mm-Mm Mmap
|
||||
|
||||
Some of the fundamental assumptions of `mmap` are that there exists a
|
||||
relatively large virtual address space, and that unmapped pages don't
|
||||
occupy actual memory. The former doesn't tend to hold in WebAssembly,
|
||||
where linear address spaces tend to be only as big as necessary.
|
||||
|
||||
For the latter, would it be possible to make a WebAssembly engine capable
|
||||
of unmapping pages in the middle of a linear memory region, and releasing
|
||||
the resources? Sure. Is this a programming technique we want WebAssembly
|
||||
programs doing in general, requiring all VMs to implement this?
|
||||
Probably not.
|
||||
|
||||
What's emerging is a sense that what we want is a core set of
|
||||
APIs that can be implemented very broadly, and then optional API
|
||||
modules that VMs can opt into supporting if it makes sense for them.
|
||||
And with this mindset, `mmap` feels like it belongs in one of these
|
||||
optional sets, rather than in the core.
|
||||
|
||||
(although note that even for the use case of reading files quickly,
|
||||
`mmap`
|
||||
[isn't always better than just reading into a buffer](https://blog.burntsushi.net/ripgrep/).
|
||||
|
||||
## A WebAssembly port of Debian?
|
||||
|
||||
This is a thought-experiment. Debian is ported to numerous hardware
|
||||
architectures. WebAssembly in some settings is presented as a hardware
|
||||
architecture. Would it make sense to port the Debian userspace to
|
||||
WebAssembly? What would this look like? What would it be useful for?
|
||||
|
||||
It would be kind of cool to have a WebAssembly-powered Unix shell
|
||||
environment or even a graphical desktop environment running inside a
|
||||
browser. But would it be *really* cool? Significantly more cool than,
|
||||
say, an SSH or VNC session to an instance in the cloud? Because to do
|
||||
much with it, you'll want a filesystem, a network stack, and so on,
|
||||
and there's only so much that browsers will let you do.
|
||||
|
||||
To be sure, it certainly would be cool. But there's a tendency in
|
||||
some circles to think of something like Debian as the natural end goal
|
||||
in a system API and toolchain for WebAssembly. We feel this tendency
|
||||
too ourselves. But it's never really been clear how it's supposed to
|
||||
work.
|
||||
|
||||
The insight here is that we can split the design space, rather than
|
||||
trying to solve everything at once. We can have a core set of APIs
|
||||
that will be enough for most applications, but that doesn't try to
|
||||
support all of Debian userland. This will make implementations more
|
||||
portable, flexible, testable, and robust than if we tried to make
|
||||
every implementation support everything, or come up with custom
|
||||
subsets.
|
||||
|
||||
As mentioned above, there is room for additional optional APIs to be
|
||||
added beyond the core WASI set. And there's absolutely a place for
|
||||
tools and libraries that features that aren't in the standard
|
||||
platform. So people interested in working on a Debian port can still
|
||||
have a path forward, but we don't need to let this become a focus for
|
||||
the core WASI design.
|
||||
|
||||
## A picture emerges
|
||||
|
||||
While much of what's written here seems relatively obvious in
|
||||
retrospect, this clarity is relatively new. We're now seeing many of the
|
||||
ideas which have been swirling around, some as old as WebAssembly
|
||||
itself, come together into a cohesive overall plan, which makes this
|
||||
an exciting time.
|
||||
|
||||
[POSIX]: http://pubs.opengroup.org/onlinepubs/9699919799/
|
||||
78
docs/WASI-capabilities.md
Normal file
78
docs/WASI-capabilities.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Additional background on Capabilities
|
||||
|
||||
## Unforgeable references
|
||||
|
||||
One of the key words that describes capabilities is *unforgeable*.
|
||||
|
||||
A pointer in C is forgeable, because untrusted code could cast an integer
|
||||
to a pointer, thus *forging* access to whatever that pointer value points
|
||||
to.
|
||||
|
||||
MVP WebAssembly doesn't have unforgeable references, but what we can do instead
|
||||
is just use integer values which are indices into a table that's held outside
|
||||
the reach of untrusted code. The indices themselves are forgeable, but
|
||||
ultimately the table is the thing which holds the actual capabilities, and
|
||||
its elements are unforgeable. There's no way to gain access to a new resource
|
||||
by making up a new index.
|
||||
|
||||
When the reference-types proposal lands, references will be unforgeable, and
|
||||
will likely subsume the current integer-based APIs, at the WASI API layer.
|
||||
|
||||
## Static vs dynamic capabilities
|
||||
|
||||
There are two levels of capabilities that we can describe: static and dynamic.
|
||||
|
||||
The static capabilities of a wasm module are its imports. These essentially
|
||||
declare the set of "rights" the module itself will be able to request.
|
||||
An important caveat though is that this doesn't consider capabilities which
|
||||
may be passed into an instance at runtime.
|
||||
|
||||
The dynamic capabilities of a wasm module are a set of boolean values
|
||||
associated with a file descriptor, indicating individual "rights". This
|
||||
includes things like the right to read, or to write, using a given file
|
||||
descriptor.
|
||||
|
||||
## Filesystem rules
|
||||
|
||||
It happens that integer indices representing capabilities is same thing that
|
||||
POSIX does, except that POSIX calls these indices *file descriptors*.
|
||||
|
||||
One difference though is that POSIX normally allows processes to request
|
||||
a file descriptor for any file in the entire filesystem hierarchy, which is
|
||||
granted based on whatever security policies are in place. This doesn't
|
||||
violate the capability model, but it doesn't take full advantage of it.
|
||||
|
||||
CloudABI, Fuchsia, and other capability-oriented systems prefer to take
|
||||
advantage of the hierarchical nature of the filesystem and require untrusted
|
||||
code to have a capability for a directory in order to access things inside
|
||||
that directory.
|
||||
|
||||
So you can launch untrusted code, and at runtime give it access to specific
|
||||
directories, without having to set permissions in the filesystem or in
|
||||
per-application or per-user configuration settings.
|
||||
|
||||
## Berkeley socket rules
|
||||
|
||||
Sockets aren't naturally hierarchical though, so we'll need to decide what
|
||||
capabilities look like. This is an area that isn't yet implemented.
|
||||
|
||||
In CloudABI, users launch programs with the sockets they need already
|
||||
created. That's a potentially startup point, which might be enough for
|
||||
simple cases.
|
||||
|
||||
We also anticipate an eventual extension to that, where we create a capability
|
||||
that represents a set of possible sockets that can be created. A set
|
||||
might be described by ranges of permitted ports, ranges of permitted
|
||||
addresses, or sets of permitted protocols. In this case the actual socket
|
||||
wouldn't be created until the application actually requests it.
|
||||
|
||||
## Other info
|
||||
|
||||
CloudABI's intro to capability-based OS security provides additional background info:
|
||||
|
||||
https://github.com/NuxiNL/cloudabi#capability-based-security
|
||||
|
||||
|
||||
The Fuchsia project has a blog post on the topic of capability-based OS security:
|
||||
|
||||
https://fuchsia.googlesource.com/docs/+/HEAD/the-book/dotdot.md
|
||||
22
docs/WASI-documents.md
Normal file
22
docs/WASI-documents.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# WASI Document Guide
|
||||
|
||||
To get started using WASI, see [the intro document](WASI-intro.md) and
|
||||
[the tutorial](WASI-tutorial.md).
|
||||
|
||||
For more detail on what WASI is, see [the overview](WASI-overview.md).
|
||||
|
||||
For specifics on the API, see the [API documentation](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-api.md).
|
||||
Additionally, a C header file describing the WASI API is
|
||||
[here](https://github.com/CraneStation/reference-sysroot-wasi/blob/misc/libc-bottom-half/headers/public/wasi/core.h).
|
||||
|
||||
For some discussion of capability-based design, see the [Capabilities document](WASI-capabilities.md).
|
||||
|
||||
For some discussion of WASI's design inspiration, see the [Background document](WASI-background.md).
|
||||
|
||||
For background on some of the design decisions in WASI, see [the rationale](WASI-rationale.md).
|
||||
|
||||
For some ideas of things that we may want to change about WASI in the
|
||||
short term, see the [possible changes](WASI-some-possible-changes.md) document.
|
||||
For longer-term ideas, see the [possible future features](WASI-possible-future-features.md)
|
||||
document.
|
||||
|
||||
83
docs/WASI-intro.md
Normal file
83
docs/WASI-intro.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Welcome to WASI!
|
||||
|
||||
WASI stands for WebAssembly System Interface. It's an API designed by
|
||||
the [Wasmtime] project that provides access to several operating-system-like
|
||||
features, including files and filesystems, Berkeley sockets, clocks, and
|
||||
random numbers, that we'll be proposing for standardization.
|
||||
|
||||
It's designed to be independent of browsers, so it doesn't depend on
|
||||
Web APIs or JS, and isn't limited by the need to be compatible with JS.
|
||||
And it has integrated capability-based security, so it extends
|
||||
WebAssembly's characteristic sandboxing to include I/O.
|
||||
|
||||
See the [WASI Overview](WASI-overview.md) for more detailed background
|
||||
information, and the [WASI Tutorial](WASI-tutorial.md) for a walkthrough
|
||||
showing how various pieces fit together.
|
||||
|
||||
Note that everything here is a prototype, and while a lot of stuff works,
|
||||
there are numerous missing features and some rough edges. One big thing
|
||||
that's not done yet is the actual mechanism to provide a directory as a
|
||||
pre-opened capability, to allow files to be opened. Some of the pieces
|
||||
are there (`__wasilibc_register_preopened_fd`) but they're not used yet.
|
||||
Networking support is also incomplete.
|
||||
|
||||
## How can I write programs that use WASI?
|
||||
|
||||
The two toolchains that currently work well are the Rust toolchain and
|
||||
a specially packaged C and C++ toolchain. Of course, we hope other
|
||||
toolchains will be able to implement WASI as well!
|
||||
|
||||
### Rust
|
||||
|
||||
To install a WASI-enabled Rust toolchain, follow the instructions here:
|
||||
|
||||
https://github.com/alexcrichton/rust/releases/tag/wasi3
|
||||
|
||||
Until now, Rust's WebAssembly support has had two main options, the
|
||||
Emscripten-based option, and the wasm32-unknown-unknown option. The latter
|
||||
option is lighter-weight, but only supports `no_std`. WASI enables a new
|
||||
wasm32-unknown-wasi target, which is similar to wasm32-unknown-unknown in
|
||||
that it doesn't depend on Emscripten, but it can use WASI to provide a
|
||||
decent subset of libstd.
|
||||
|
||||
### C/C++
|
||||
|
||||
All the parts needed to support wasm are included in upstream clang, lld, and
|
||||
compiler-rt, as of the LLVM 8.0 release. However, to use it, you'll need
|
||||
to build WebAssembly-targeted versions of the library parts, and it can
|
||||
be tricky to get all the CMake invocations lined up properly.
|
||||
|
||||
To make things easier, we provide
|
||||
[prebuilt packages](https://github.com/CraneStation/wasi-sdk/releases)
|
||||
that provide builds of Clang and sysroot libraries.
|
||||
|
||||
Note that C++ support has a notable
|
||||
[bug](https://bugs.llvm.org/show_bug.cgi?id=40412) in clang which affects
|
||||
<iostream> in libcxx. This will be fixed in future versions.
|
||||
|
||||
## How can I run programs that use WASI?
|
||||
|
||||
Currently the options are [Wasmtime] and the [browser polyfill], though we
|
||||
intend WASI to be implementable in many wasm VMs.
|
||||
|
||||
[Wasmtime]: https://github.com/CraneStation/wasmtime
|
||||
[browser polyfill]: https://wasi.dev/polyfill/
|
||||
|
||||
### Wasmtime
|
||||
|
||||
[Wasmtime] is a non-Web WebAssembly engine which is part of the
|
||||
[CraneStation project](https://github.com/CraneStation/). To build
|
||||
it, download the code and build with `cargo build --release`. It can
|
||||
run WASI-using wasm programs by simply running `wasmtime foo.wasm`,
|
||||
or `cargo run --bin wasmtime foo.wasm`.
|
||||
|
||||
### The browser polyfill
|
||||
|
||||
The polyfill is online [here](https://wasi.dev/polyfill/).
|
||||
|
||||
The source is [here](https://github.com/CraneStation/wasmtime-wasi/tree/wasi/lib/wasi/sandboxed-system-primitives/polyfill).
|
||||
|
||||
## Where can I learn more?
|
||||
|
||||
Beyond the [WASI Overview](WASI-overview.md), take a look at the
|
||||
various [WASI documents](WASI-documents.md).
|
||||
163
docs/WASI-overview.md
Normal file
163
docs/WASI-overview.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# WASI: WebAssembly System Interface
|
||||
|
||||
WebAssembly System Interface, or WASI, is a new family of API's being
|
||||
designed by the [Wasmtime] project to propose as a standard engine-independent
|
||||
non-Web system-oriented API for WebAssembly. Initially, the focus is on
|
||||
WASI Core, an API module that covers files, networking, and a few other
|
||||
things. Additional modules are expected to be added in the future.
|
||||
|
||||
WebAssembly is designed to run well on the Web, however it's
|
||||
[not limited to the Web](https://github.com/WebAssembly/design/blob/master/NonWeb.md).
|
||||
The core WebAssembly language is independent of its surrounding
|
||||
environment, and WebAssembly interacts with the outside world
|
||||
exclusively through APIs. On the Web, it naturally uses the
|
||||
existing Web APIs provided by browsers. However outside of
|
||||
browsers, there's currently no standard set of APIs that
|
||||
WebAssembly programs can be written to. This makes it difficult to
|
||||
create truly portable non-Web WebAssembly programs.
|
||||
|
||||
WASI is an initiative to fill this gap, with a clean set of APIs
|
||||
which can be implemented on multiple platforms by multiple engines,
|
||||
and which don't depend on browser functionality (although they
|
||||
still can run in browsers; see below).
|
||||
|
||||
## Capability-Oriented
|
||||
|
||||
The design follows
|
||||
[CloudABI](https://cloudabi.org/)'s
|
||||
(and in turn
|
||||
[Capsicum](https://www.cl.cam.ac.uk/research/security/capsicum/))'s concept of
|
||||
[capability-based security](https://en.wikipedia.org/wiki/Capability-based_security),
|
||||
which fits well into WebAssembly's sandbox model. Files,
|
||||
directories, network sockets, and other resources are identified
|
||||
by UNIX-like file descriptors, which are indices into external
|
||||
tables whose elements represent capabilities. Similar to how core
|
||||
WebAssembly provides no ability to access the outside world without
|
||||
calling imported functions, WASI APIs provide no ability to access
|
||||
the outside world without an associated capability.
|
||||
|
||||
For example, instead of a typical
|
||||
[open](http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html)
|
||||
system call, WASI provides an
|
||||
[openat](https://linux.die.net/man/2/openat)-like
|
||||
system call, requiring the calling process to have a file
|
||||
descriptor for a directory that contains the file, representing the
|
||||
capability to open files within that directory. (These ideas are
|
||||
common in capability-based systems.)
|
||||
|
||||
However, the WASI libc implementation still does provide an
|
||||
implementation of open, by taking the approach of
|
||||
[libpreopen](https://github.com/musec/libpreopen).
|
||||
Programs may be granted capabilities for directories on launch, and
|
||||
the library maintains a mapping from their filesystem path to the
|
||||
file descriptor indices representing the associated capabilities.
|
||||
When a program calls open, they look up the file name in the map,
|
||||
and automatically supply the appropriate directory capability. It
|
||||
also means WASI doesn't require the use of CloudABI's `program_main`
|
||||
construct. This eases porting of existing applications without
|
||||
compromising the underlying capability model. See the diagram below
|
||||
for how libpreopen fits into the overall software architecture.
|
||||
|
||||
WASI also automatically provides file descriptors for standard
|
||||
input and output, and WASI libc provides a normal `printf`. In
|
||||
general, WASI is aiming to support a fairly full-featured libc
|
||||
implementation, with the current implementation work being based on
|
||||
[musl](http://www.musl-libc.org/).
|
||||
|
||||
## Portable System Interface for WebAssembly
|
||||
|
||||
WASI is being designed from the ground up for WebAssembly, with
|
||||
sandboxing, portability, and API tidiness in mind, making natural
|
||||
use of WebAssembly features such as i64, import functions with
|
||||
descriptive names and typed arguments, and aiming to avoid being
|
||||
tied to a particular implementation.
|
||||
|
||||
We'll often call functions in these APIs "syscalls", because they
|
||||
serve an analogous purpose to system calls in native executables.
|
||||
However, they're just functions that are provided by the
|
||||
surrounding environment that can do I/O on behalf of the program.
|
||||
|
||||
WASI is starting with a basic POSIX-like set of syscall functions,
|
||||
though adapted to suit the needs of WebAssembly, such as in
|
||||
excluding functions such as fork and exec which aren't easily
|
||||
implementable in some of the places people want to run WebAssembly,
|
||||
and such as in adopting a capabilities-oriented design.
|
||||
|
||||
And, as WebAssembly grows support for
|
||||
[host bindings](https://github.com/webassembly/host-bindings)
|
||||
and related features, capabilities can evolve to being represented
|
||||
as opaque, unforgeable
|
||||
[reference typed values](https://github.com/WebAssembly/reference-types),
|
||||
which can allow for finer-grained control over capabilities, and
|
||||
make the API more accessible beyond the C-like languages that
|
||||
POSIX-style APIs are typically aimed at.
|
||||
|
||||
## WASI Software Architecture
|
||||
|
||||
To facilitate use of the WASI API, a libc
|
||||
implementation called WASI libc is being developed, which presents
|
||||
a relatively normal musl-based libc interface, implemented on top
|
||||
of a libpreopen-like layer and a system call wrapper layer (derived
|
||||
from the "bottom half" of
|
||||
[cloudlibc](https://github.com/NuxiNL/cloudlibc)).
|
||||
The system call wrapper layer makes calls to the actual WASI
|
||||
implementation, which may map these calls to whatever the
|
||||
surrounding environment provides, whether it's native OS resources,
|
||||
JS runtime resources, or something else entirely.
|
||||
|
||||
[This libc is part of a "sysroot"](https://github.com/WebAssembly/reference-sysroot),
|
||||
which is a directory containing compiled libraries and C/C++ header
|
||||
files providing standard library and related facilities laid out in
|
||||
a standard way to allow compilers to use it directly.
|
||||
|
||||
With the [LLVM 8.0](http://llvm.org/)
|
||||
release, the WebAssembly backend is now officially stable, but LLVM
|
||||
itself doesn't provide a libc - a standard C library, which you
|
||||
need to build anything with clang. This is what the WASI-enabled
|
||||
sysroot provides, so the combination of clang in LLVM 8.0 and the
|
||||
new WASI-enabled sysroot provides usable Rust and C compilation
|
||||
environments that can produce wasm modules that can be run in
|
||||
[Wasmtime] with WASI support, in browsers with the WASI polyfill,
|
||||
and in the future other engines as well.
|
||||
|
||||

|
||||
|
||||
## Future Evolution
|
||||
|
||||
The first version of WASI is relatively simple, small, and
|
||||
POSIX-like in order to make it easy for implementers to prototype
|
||||
it and port existing code to it, making it a good way to start
|
||||
building momentum and allow us to start getting feedback based on
|
||||
experience.
|
||||
|
||||
Future versions will change based on experience
|
||||
and feedback with the first version, and add features to address
|
||||
new use cases. They may also see significant architectural
|
||||
changes. One possibility is that this API could
|
||||
evolve into something like
|
||||
[Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia)'s
|
||||
low-level APIs, which are more complex and abstract, though also
|
||||
more capable.
|
||||
|
||||
We also expect that whatever WASI evolves into in the future, it
|
||||
should be possible to implement this initial API as a library
|
||||
on top.
|
||||
|
||||
## Can WASI apps run on the Web?
|
||||
|
||||
Yes! We have a polyfill which implements WASI and runs in browsers.
|
||||
At the WebAssembly level, WASI is just a set of callable functions that
|
||||
can be imported by a .wasm module, and these imports can be implemented
|
||||
in a variety of ways, including by a JavaScript polyfill library running
|
||||
within browsers.
|
||||
|
||||
And in the future, it's possible that
|
||||
[builtin modules](https://github.com/tc39/ecma262/issues/395)
|
||||
could take these ideas even further allowing easier and tighter
|
||||
integration between .wasm modules importing WASI and the Web.
|
||||
|
||||
## Work in Progress
|
||||
|
||||
WASI is currently experimental. Feedback is welcome!
|
||||
|
||||
[Wasmtime]: https://github.com/CraneStation/wasmtime
|
||||
49
docs/WASI-possible-future-features.md
Normal file
49
docs/WASI-possible-future-features.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Possible Future Features
|
||||
|
||||
This are features we're interested in, but don't have yet, and which will require
|
||||
some amount of design work.
|
||||
|
||||
## File Locking
|
||||
|
||||
POSIX's answer is `fcntl` with `F_SETLK`/`F_GETLK`/etc., which provide advisory
|
||||
record locking. Unfortunately, these locks are associated with processes, which
|
||||
means that if two parts of a program independently open a file and try to lock
|
||||
it, if they're in the same process, they automatically share the lock.
|
||||
|
||||
Other locking APIs exist on various platforms, but none is widely standardized.
|
||||
|
||||
POSIX `F_SETLK`-style locking is used by SQLite.
|
||||
|
||||
## File change monitoring
|
||||
|
||||
POSIX has no performant way to monitor many files or directories for changes.
|
||||
|
||||
Many popular operating systems have system-specific APIs to do this though, so
|
||||
it'd be desirable to come up with a portable API to provide access to this
|
||||
functionality.
|
||||
|
||||
## Scalable event-based I/O
|
||||
|
||||
POSIX's `select` and `poll` have the property that each time they're called,
|
||||
the implementation has to scan through all the file descriptors to report if any
|
||||
of them has I/O ready, which is inefficient when there are large numbers of
|
||||
open files or sockets.
|
||||
|
||||
Many popular operating systems have system-specific APIs that provide
|
||||
alternative ways to monitor large numbers of I/O streams though, so it'd be
|
||||
desirable to come up with a portable API to provide access to this
|
||||
functionality.
|
||||
|
||||
## Crash recovery
|
||||
|
||||
POSIX doesn't have clear guidance on what applications can expect their
|
||||
data will look like if the system crashes or the storage device is otherwise
|
||||
taken offline abruptly.
|
||||
|
||||
We have `fsync` and `fdatasync`, but even these have been a topic of
|
||||
[much discussion].
|
||||
|
||||
[much discussion]: https://wiki.postgresql.org/wiki/Fsync_Errors
|
||||
|
||||
Also, currently WASI's docs don't make any guarantees about things like
|
||||
`path_rename` being atomic.
|
||||
160
docs/WASI-rationale.md
Normal file
160
docs/WASI-rationale.md
Normal file
@@ -0,0 +1,160 @@
|
||||
## Why not a more traditional set of POSIX-like syscalls?
|
||||
|
||||
In related work, the LLVM wasm backend started out trying to use ELF object
|
||||
files for wasm, to be as conventional as possible. But wasm doesn't fit into
|
||||
ELF in some very fundamental ways. Code isn't in the address space, callers
|
||||
have to know their callee's exact signatures, imports and exports don't have
|
||||
ELF semantics, function pointers require tables to be populated, index 0 is
|
||||
valid in some contexts where it isn't in ELF, and so on. It ultimately got
|
||||
to the point where the work we were considering doing to *emulate* ELF
|
||||
interfaces to make existing tools happy looked like more than the work that
|
||||
would be required to just build new tools.
|
||||
|
||||
The analogy isn't perfect, but there are some parallels to what we're now
|
||||
figuring out about system calls. Many people, including us, had initially
|
||||
assumed that at least some parts of the wasm ecosystem would eventually
|
||||
standardize on a basic map of POSIX-like or Linux-like system calls into wasm
|
||||
imports. However, this turns out to be more complex than it initially seems.
|
||||
|
||||
One of WebAssembly's unique attributes is the ability to run sandboxed
|
||||
without relying on OS process boundaries. Requiring a 1-to-1 correspondence
|
||||
between wasm instances and heavyweight OS processes would take away this key
|
||||
advantage for many use cases. Fork/exec are the obvious example of an API
|
||||
that's difficult to implement well if you don't have POSIX-style processes,
|
||||
but a lot of other things in POSIX are tied to processes too. So it isn't
|
||||
a simple matter to take POSIX, or even a simple subset of it, to WebAssembly.
|
||||
|
||||
We should note that Spectre concerns are relevant here, though for now we'll
|
||||
just observe that actual security depends on the details of implementations
|
||||
and use cases, and it's not necessarily a show-stopper.
|
||||
|
||||
Another area where WebAssembly differs from traditional POSIX-like platforms
|
||||
is in its Capability-oriented approach to security. WebAssembly core has no
|
||||
ability to address the outside world, except through interacting with
|
||||
imports/exports. And when reference types are added, they'll be able to
|
||||
represent very fine-grained and dynamic capabilities.
|
||||
|
||||
A capability-oriented system interface fits naturally into WebAssembly's
|
||||
existing sandbox model, by extending the simple story that a wasm module
|
||||
can't do anything until given capabilities. There are ways to sandbox
|
||||
traditional OS filesystem APIs too, but in a multiple-implementation
|
||||
ecosystem where the methods for setting up path filtering will likely
|
||||
differ between implementations, designing the platform around capabilities
|
||||
will make it easier for people to consistently configure the capabilities
|
||||
available to wasm modules.
|
||||
|
||||
This is where we see WASI heading.
|
||||
|
||||
## Why not non-blocking?
|
||||
|
||||
This is an open question. We're using blocking APIs for now because that's
|
||||
*by far* the simpler way to get the overall system to a usable state, on
|
||||
both the wasm runtime side and the toolchain side. But one can make an
|
||||
argument that non-blocking APIs would have various advantages, so we
|
||||
look forward to discussing this topic with the WebAssembly CG subgroup
|
||||
once it's set up.
|
||||
|
||||
## Why not async?
|
||||
|
||||
We have some ideas about how the current API could be extended to be async.
|
||||
In particular, we can imagine making a distinction between WebAssembly
|
||||
programs which are *Commands* and those which we'll call *Reactors*.
|
||||
Commands have a `main` function which is called once, and when `main`
|
||||
exits, the program is complete. Reactors have a setup function, but
|
||||
once that completes, the instance remains live and is called from callbacks.
|
||||
In a Reactor, there's an event loop which lives outside of the nominal
|
||||
program.
|
||||
|
||||
With this distinction, we may be able to say things like:
|
||||
- In a Reactor, WASI APIs are available, but all functions have an
|
||||
additional argument, which specifies a function to call as a continuation
|
||||
once the I/O completes. This way, we can use the same conceptual APIs,
|
||||
but adapt them to run in an callback-based async environment.
|
||||
- In a Command, WASI APIs don't have callback parameters. Whether or not
|
||||
they're non-blocking is an open question (see the previous question).
|
||||
|
||||
Reactors might then be able to run in browsers on the main thread,
|
||||
while Commands in browsers might be limited to running in Workers.
|
||||
|
||||
## Why no mmap and friends?
|
||||
|
||||
True mmap support is something that could be added in the future,
|
||||
though it is expected to require integration with the core language.
|
||||
See "Finer-grained control over memory" in WebAssembly's
|
||||
[Future Features] document for an overview.
|
||||
|
||||
Ignoring the many non-standard mmap extensions out there,
|
||||
the core mmap behavior is not portable in several respects, even
|
||||
across POSIX-style systems. See
|
||||
[LevelDB's decision to stop using mmap], for one example in
|
||||
practice, and search for the word "unspecified" in the
|
||||
[POSIX mmap spec] for some others.
|
||||
|
||||
And, some features of mmap can lead to userspace triggering
|
||||
signals. Accessing memory beyond the end of the file, including in
|
||||
the case where someone else changes the size of the file, leads to a
|
||||
`SIGBUS` on POSIX-style systems. Protection modes other than
|
||||
`PROT_READ|PROT_WRITE` can produce `SIGSEGV`. While some VMs are
|
||||
prepared to catch such signals transparently, this is a burdensome
|
||||
requirement for others.
|
||||
|
||||
Another issue is that while WASI is a synchronous I/O API today,
|
||||
this design may change in the future. `mmap` can create situations
|
||||
where doing a load can entail blocking I/O, which can make it
|
||||
harder to characterize all the places where blocking I/O may occur.
|
||||
|
||||
And lastly, WebAssembly linear memory doesn't support the semantics
|
||||
of mapping and unmapping pages. Most WebAssembly VMs would not
|
||||
easily be able to support freeing the memory of a page in the middle
|
||||
of a linear memory region, for example.
|
||||
|
||||
To make things easier for people porting programs that just use
|
||||
mmap to read and write files in a simple way, WASI libc includes a
|
||||
minimal userspace emulation of `mmap` and `munmap`.
|
||||
|
||||
[POSIX mmap spec]: http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html
|
||||
[LevelDB's decision to stop using mmap]: https://groups.google.com/forum/#!topic/leveldb/C5Hh__JfdrQ
|
||||
[Future Features]: https://webassembly.org/docs/future-features/.
|
||||
|
||||
## Why no UNIX-domain sockets?
|
||||
|
||||
UNIX-domain sockets can communicate three things:
|
||||
- bytes
|
||||
- file descriptors
|
||||
- user credentials
|
||||
|
||||
The concept of "users" doesn't fit within WASI, because many implementations
|
||||
won't be multi-user in that way.
|
||||
|
||||
It can be useful to pass file descriptor between wasm instances, however in
|
||||
wasm this can be done by passing them as arguments in plain function calls,
|
||||
which is much simpler and quicker. And, in WASI implementations where file
|
||||
descriptors don't correspond to an underlying Unix file descriptor concept,
|
||||
it's not feasible to do this if the other side of the socket isn't a
|
||||
cooperating WebAssembly engine.
|
||||
|
||||
We may eventually want to introduce a concept of a WASI-domain socket, for
|
||||
bidirectional byte-oriented local communication.
|
||||
|
||||
## Why no dup?
|
||||
|
||||
The main use cases for `dup` are setting up the classic Unix dance of setting
|
||||
up file descriptors in advance of performing a `fork`. Since WASI has no `fork`,
|
||||
these don't apply.
|
||||
|
||||
And avoiding `dup` for now avoids committing to the POSIX concepts of
|
||||
descriptors being distinct from file descriptions in subtle ways.
|
||||
|
||||
## Why are `path_remove_directory` and `path_unlink_file` separate syscalls?
|
||||
|
||||
In POSIX, there's a single `unlinkat` function, which has a flag word,
|
||||
and with the `AT_REMOVEDIR` flag one can specify whether one wishes to
|
||||
remove a file or a directory. However, there really are two distinct
|
||||
functions being performed here, and having one system call that can
|
||||
select between two different behaviors doesn't simplify the actual API
|
||||
compared to just having two system calls.
|
||||
|
||||
More importantly, in WASI, system call imports represent a static list
|
||||
of the capabilities requested by a wasm module. Therefore, WASI prefers
|
||||
each system call to do just one thing, so that it's clear what a wasm
|
||||
module that imports it might be able to do with it.
|
||||
114
docs/WASI-some-possible-changes.md
Normal file
114
docs/WASI-some-possible-changes.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Possible changes
|
||||
|
||||
The following are a list of relatively straightforward changes
|
||||
to WASI core that should be considered.
|
||||
|
||||
## Split file/networking/random/clock from args/environ/exit.
|
||||
|
||||
Currently everything is mixed together in one big "core" module. But we can
|
||||
split them out to allow minimal configurations that don't support this style
|
||||
of files and networking.
|
||||
|
||||
## Move higher-level and unused errno codes out of the core API.
|
||||
|
||||
The core API currently defines errno codes such as `EDOM` which are
|
||||
not used for anything. POSIX requires them to be defined, however
|
||||
that can be done in the higher-level libraries, rather than in the
|
||||
WASI core API itself.
|
||||
|
||||
## Detecting EOF from read/recv explicitly.
|
||||
|
||||
POSIX's `read` returns 0 if and only if it reaches the end of a file or stream.
|
||||
|
||||
Say you have a read buffer of 1024 bytes, and are reading a file that happens
|
||||
to be 7 bytes long. The first `read` call will return 7, but unless you happen
|
||||
to know how big the file is supposed to be, you can't distinguish between
|
||||
that being all there is, and `read` getting interrupted and returning less
|
||||
data than you requested.
|
||||
|
||||
Many applications today do an extra `read` when they encounter the end of a
|
||||
file, to ensure that they get a `read` that returns 0 bytes read, to confirm
|
||||
that they've reached the end of the file. If `read` instead had a way to
|
||||
indicate that it had reached the end, this extra call wouldn't be necessary.
|
||||
|
||||
And, `read` on a socket is almost equivalent to `recv` with no flags -- except for
|
||||
one surprising special case: on a datagram socket, if there's a zero-length
|
||||
datagram, `read` can't consume it, while `recv` can. This is because `read` can't
|
||||
indicate that it successfully read 0 bytes, because it has overloaded the meaning
|
||||
of 0 to indicate eof-of-file.
|
||||
|
||||
So, it would be tidier from multiple perspectives if `read` could indicate
|
||||
that it had reached the end of a file or stream, independently of how many
|
||||
bytes it has read.
|
||||
|
||||
## Merging read and recv
|
||||
|
||||
These are very similar, and differ only in subtle ways. It'd make the API
|
||||
easier to understand if they were unified.
|
||||
|
||||
## Trap instead of returning EFAULT
|
||||
|
||||
POSIX system calls return EFAULT when given invalid pointers, however from an
|
||||
application perspective, it'd be more natural for them to just segfault.
|
||||
|
||||
## More detailed capability error reporting
|
||||
|
||||
Replace `__WASI_ENOTCAPABLE` with error codes that indicate *which* capabilities
|
||||
were required but not present.
|
||||
|
||||
## Split `__wasi_path_open` into `__wasi_path_open_file` and `__wasi_path_open_directory`?
|
||||
|
||||
We could also split `__WASI_RIGHT_PATH_OPEN` into file vs directory,
|
||||
(obviating `__WASI_O_DIRECTORY`).
|
||||
|
||||
## Fix the y2556 bug
|
||||
|
||||
In some places, timestamps are measured in nanoseconds since the UNIX epoch,
|
||||
so our calculations indicate a 64-bit counter will overflow on
|
||||
Sunday, July 21, 2554, at 11:34:33 pm UTC.
|
||||
|
||||
These timestamps aren't used in that many places, so it wouldn't cost that
|
||||
much to widen these timestamps. We can either just extend the current type to
|
||||
128 bits (two i64's in wasm) or move to a `timespec`-like `tv_sec`/`tv_nsec`
|
||||
pair.
|
||||
|
||||
## Remove `fd_allocate`?
|
||||
|
||||
Darwin doesn't implement `fd_allocate`, despite it being a in POSIX
|
||||
since 2001. So we don't currently know any way to implement `fd_allocate`
|
||||
on Darwin that's safe from race conditions. Should we remove it from the API?
|
||||
|
||||
## Redesign `fstflags_t`
|
||||
|
||||
The relationship between `*_SET_*TIM` and `*_SET_*TIM_NOW` is non-obvious.
|
||||
We should look at this again.
|
||||
|
||||
## readdir
|
||||
|
||||
Truncating entries that don't fit into a buffer may be error-prone. Should
|
||||
we redesign how directory reading works?
|
||||
|
||||
## symlinks
|
||||
|
||||
Symlinks are fairly UNIX-specific. Should we remove `__wasi_path_symlink`
|
||||
and `__wasi_path_readlink`?
|
||||
|
||||
Also, symlink resolution doesn't benefit from libpreopen-style path
|
||||
translation. Should we move symlink resolution into the libpreopen layer
|
||||
and do it entirely in "userspace"?
|
||||
|
||||
## Remove the `path_len` argument from `__wasi_fd_prestat_dir_name`
|
||||
|
||||
The buffer should be sized to the length returned from `__wasi_fd_prestat_get`,
|
||||
so it's not necessary to pass the length back into the runtime.
|
||||
|
||||
## Add a `__wasi_path_filestat_set_size` function?
|
||||
|
||||
Along with libc/libpreopen support, this would enable implementing the
|
||||
POSIX `truncate` function.
|
||||
|
||||
## errno values returned by `path_open`
|
||||
|
||||
We should specify the errno value returned when `path_open` is told
|
||||
to open a directory and `__WASI_LOOKUP_SYMLINK_FOLLOW` isn't set, and
|
||||
the path refers to a symbolic link.
|
||||
159
docs/WASI-tutorial.md
Normal file
159
docs/WASI-tutorial.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# WASI tutorial
|
||||
|
||||
Let's start with a simple C program which performs a file copy, which will
|
||||
show to compile and run programs, as well as perform simple sandbox
|
||||
configuration. The C code here uses standard POSIX APIs, and doesn't have
|
||||
any knowledge of WASI, WebAssembly, or sandboxing.
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
int n, m;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s <from> <to>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int in = open(argv[1], O_RDONLY);
|
||||
if (in < 0) {
|
||||
fprintf(stderr, "error opening input %s: %s\n", argv[1], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int out = open(argv[2], O_WRONLY | O_CREAT, 0660);
|
||||
if (out < 0) {
|
||||
fprintf(stderr, "error opening output %s: %s\n", argv[2], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((n = read(in, buf, BUFSIZ)) > 0) {
|
||||
while (n > 0) {
|
||||
m = write(out, buf, n);
|
||||
if (m < 0) {
|
||||
fprintf(stderr, "write error: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
n -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "read error: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
We'll put this source in a file called `demo.c`.
|
||||
|
||||
The [wasi-sdk](https://github.com/CraneStation/wasi-sdk/releases) provides a clang
|
||||
which is configured to target WASI and use the WASI sysroot by default, so we can
|
||||
compile our program like so:
|
||||
|
||||
```
|
||||
$ clang demo.c
|
||||
```
|
||||
|
||||
A few things to note here. First, this is just regular clang, configured to use
|
||||
a WebAssembly target and sysroot. The name `a.out` is the traditional default
|
||||
output name that C compilers use, and can be overridden with the "-o" flag in the
|
||||
usual way. And, the output of clang here is a standard WebAssembly module:
|
||||
|
||||
```
|
||||
$ file a.out
|
||||
a.out: WebAssembly (wasm) binary module version 0x1 (MVP)
|
||||
```
|
||||
|
||||
It's a single file containing a self-contained wasm module, that doesn't require
|
||||
any supporting JS code.
|
||||
|
||||
We can execute it with wasmtime directly, like so:
|
||||
|
||||
```
|
||||
$ wasmtime a.out
|
||||
usage: a.out <from> <to>
|
||||
```
|
||||
|
||||
Ok, this program needs some command-line arguments. So let's give it some:
|
||||
|
||||
```
|
||||
$ echo hello world > test.txt
|
||||
$ wasmtime a.out test.txt /tmp/somewhere.txt
|
||||
error opening input test.txt: Capabilities insufficient
|
||||
```
|
||||
|
||||
Aha, now we're seeing the sandboxing in action. This program is attempting to
|
||||
access a file by the name of `test.txt`, however it hasn't been given the
|
||||
capability to do so.
|
||||
|
||||
So let's give it capabilities to access files in the requisite directories:
|
||||
|
||||
```
|
||||
$ wasmtime --dir=. --dir=/tmp a.out test.txt /tmp/somewhere.txt
|
||||
$ cat /tmp/somewhere.txt
|
||||
hello world
|
||||
```
|
||||
|
||||
Now our program runs as expected!
|
||||
|
||||
As a brief aside, note that we used the path `.` above to grant the program
|
||||
access to the current directory. This is needed because the mapping from
|
||||
paths to associated capabilities is performed by libc, so it's part of the
|
||||
WebAssembly program, and we don't expose the actual current working
|
||||
directory to the WebAssembly program. So providing a full path doesn't work:
|
||||
|
||||
```
|
||||
$ wasmtime --dir=$PWD --dir=/tmp a.out test.txt /tmp/somewhere.txt
|
||||
$ cat /tmp/somewhere.txt
|
||||
error opening input test.txt: Capabilities insufficient
|
||||
```
|
||||
|
||||
So, we always have to use `.` to refer to the current directory.
|
||||
|
||||
Speaking of `.`, what about `..`? Does that give programs a way to break
|
||||
out of the sandbox? Let's see:
|
||||
|
||||
```
|
||||
$ wasmtime --dir=. --dir=/tmp a.out test.txt /tmp/../etc/passwd
|
||||
$ cat /tmp/somewhere.txt
|
||||
error opening output /tmp/../etc/passwd: Capabilities insufficient
|
||||
```
|
||||
|
||||
The sandbox says no. And note that this is the capabilities system saying no
|
||||
here ("Capabilities insufficient"), rather than Unix access controls
|
||||
("Permission denied"). Even if the user running wasmtime had write access to
|
||||
`/etc/passwd`, WASI programs don't have the capability to access files outside
|
||||
of the directories they've been granted. This is true when resolving symbolic
|
||||
links as well.
|
||||
|
||||
Wasmtime also has the ability to remap directories, with the `--mapdir`
|
||||
command-line option:
|
||||
|
||||
```
|
||||
$ wasmtime --dir=. --mapdir=/tmp:/var/tmp a.out test.txt /tmp/somewhere.txt
|
||||
$ cat /var/tmp/somewhere.txt
|
||||
hello world
|
||||
```
|
||||
|
||||
This maps the name `/tmp` within the WebAssembly program to `/var/tmp` in the
|
||||
host filesystem. So the WebAssembly program itself never sees the `/var/tmp` path,
|
||||
but that's where the output file goes.
|
||||
|
||||
See [here](WASI-capabilities.md) for more information on the capability-based
|
||||
security model.
|
||||
|
||||
The capability model is very powerful, and what's shown here is just the beginning.
|
||||
In the future, we'll be exposing much more functionality, including finer-grained
|
||||
capabilities, capabilities for network ports, and the ability for applications to
|
||||
explicitly request capabilities.
|
||||
141
src/wasmtime.rs
141
src/wasmtime.rs
@@ -37,16 +37,20 @@ use cranelift_codegen::settings;
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
use cranelift_native;
|
||||
use docopt::Docopt;
|
||||
use errno::errno;
|
||||
use file_per_thread_logger;
|
||||
use pretty_env_logger;
|
||||
use std::error::Error;
|
||||
use std::ffi::{CString, OsStr};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Component;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::exit;
|
||||
use wabt;
|
||||
use wasmtime_jit::{ActionOutcome, Context};
|
||||
use wasmtime_wasi::instantiate_wasi;
|
||||
use wasmtime_wast::instantiate_spectest;
|
||||
|
||||
static LOG_FILENAME_PREFIX: &str = "wasmtime.dbg.";
|
||||
@@ -59,8 +63,8 @@ including calling the start function if one is present. Additional functions
|
||||
given with --invoke are then called.
|
||||
|
||||
Usage:
|
||||
wasmtime [-odg] <file>...
|
||||
wasmtime [-odg] <file>... --invoke=<fn>
|
||||
wasmtime [-odg] [--preload=<wasm>...] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] <file> [<arg>...]
|
||||
wasmtime [-odg] [--preload=<wasm>...] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] --invoke=<fn> <file> [<arg>...]
|
||||
wasmtime --help | --version
|
||||
|
||||
Options:
|
||||
@@ -68,17 +72,27 @@ Options:
|
||||
-o, --optimize runs optimization passes on the translated functions
|
||||
-g generate debug information
|
||||
-d, --debug enable debug output on stderr/stdout
|
||||
--preload=<wasm> load an additional wasm module before loading the main module
|
||||
--env=<env> pass an environment variable (\"key=value\") to the program
|
||||
--dir=<dir> grant access to the given host directory
|
||||
--mapdir=<mapping> where <mapping> has the form <wasmdir>:<hostdir>, grant access to
|
||||
the given host directory with the given wasm directory name
|
||||
-h, --help print this help message
|
||||
--version print the Cranelift version
|
||||
";
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
struct Args {
|
||||
arg_file: Vec<String>,
|
||||
arg_file: String,
|
||||
arg_arg: Vec<String>,
|
||||
flag_optimize: bool,
|
||||
flag_debug: bool,
|
||||
flag_g: bool,
|
||||
flag_invoke: Option<String>,
|
||||
flag_preload: Vec<String>,
|
||||
flag_env: Vec<String>,
|
||||
flag_dir: Vec<String>,
|
||||
flag_mapdir: Vec<String>,
|
||||
}
|
||||
|
||||
fn read_to_end(path: PathBuf) -> Result<Vec<u8>, io::Error> {
|
||||
@@ -100,6 +114,91 @@ fn read_wasm(path: PathBuf) -> Result<Vec<u8>, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_preopen_dirs(flag_dir: &[String], flag_mapdir: &[String]) -> Vec<(String, libc::c_int)> {
|
||||
let mut preopen_dirs = Vec::new();
|
||||
|
||||
for dir in flag_dir {
|
||||
let fd = unsafe {
|
||||
libc::open(
|
||||
CString::new(dir.as_bytes()).unwrap().as_ptr(),
|
||||
libc::O_RDONLY | libc::O_DIRECTORY,
|
||||
)
|
||||
};
|
||||
if fd < 0 {
|
||||
println!("error while pre-opening directory {}: {}", dir, errno());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
preopen_dirs.push((dir.clone(), fd));
|
||||
}
|
||||
|
||||
for mapdir in flag_mapdir {
|
||||
let parts: Vec<&str> = mapdir.split(':').collect();
|
||||
if parts.len() != 2 {
|
||||
println!("--mapdir argument must contain exactly one colon, separating a guest directory name and a host directory name");
|
||||
exit(1);
|
||||
}
|
||||
let (key, value) = (parts[0], parts[1]);
|
||||
let fd = unsafe {
|
||||
libc::open(
|
||||
CString::new(value.as_bytes()).unwrap().as_ptr(),
|
||||
libc::O_RDONLY | libc::O_DIRECTORY,
|
||||
)
|
||||
};
|
||||
if fd < 0 {
|
||||
println!("error while pre-opening directory {}: {}", value, errno());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
preopen_dirs.push((key.to_string(), fd));
|
||||
}
|
||||
|
||||
preopen_dirs
|
||||
}
|
||||
|
||||
/// Compute the argv array values.
|
||||
fn compute_argv(argv0: &str, arg_arg: &[String]) -> Vec<String> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
// Add argv[0], which is the program name. Only include the base name of the
|
||||
// main wasm module, to avoid leaking path information.
|
||||
result.push(
|
||||
Path::new(argv0)
|
||||
.components()
|
||||
.next_back()
|
||||
.map(Component::as_os_str)
|
||||
.and_then(OsStr::to_str)
|
||||
.unwrap_or("")
|
||||
.to_owned(),
|
||||
);
|
||||
|
||||
// Add the remaining arguments.
|
||||
for arg in arg_arg {
|
||||
result.push(arg.to_owned());
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Compute the environ array values.
|
||||
fn compute_environ(flag_env: &[String]) -> Vec<(String, String)> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
// Add the environment variables, which must be of the form "key=value".
|
||||
for env in flag_env {
|
||||
let split = env.splitn(2, '=').collect::<Vec<_>>();
|
||||
if split.len() != 2 {
|
||||
println!(
|
||||
"environment variables must be of the form \"key=value\"; got \"{}\"",
|
||||
env
|
||||
);
|
||||
}
|
||||
result.push((split[0].to_owned(), split[1].to_owned()));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
.and_then(|d| {
|
||||
@@ -139,20 +238,52 @@ fn main() {
|
||||
instantiate_spectest().expect("instantiating spectest"),
|
||||
);
|
||||
|
||||
// Make wasi available by default.
|
||||
let global_exports = context.get_global_exports();
|
||||
let preopen_dirs = compute_preopen_dirs(&args.flag_dir, &args.flag_mapdir);
|
||||
let argv = compute_argv(&args.arg_file, &args.arg_arg);
|
||||
let environ = compute_environ(&args.flag_env);
|
||||
context.name_instance(
|
||||
"wasi_unstable".to_owned(),
|
||||
instantiate_wasi("", global_exports, &preopen_dirs, &argv, &environ)
|
||||
.expect("instantiating wasi"),
|
||||
);
|
||||
|
||||
// FIXME: Also recognize "env", for compatibility with clang/llvm 8.0. And use
|
||||
// "__wasi_" prefixes for compaitility with prototype reference-sysroot.
|
||||
let global_exports = context.get_global_exports();
|
||||
context.name_instance(
|
||||
"env".to_owned(),
|
||||
instantiate_wasi("__wasi_", global_exports, &preopen_dirs, &argv, &environ)
|
||||
.expect("instantiating wasi"),
|
||||
);
|
||||
|
||||
// Enable/disable producing of debug info.
|
||||
context.set_debug_info(args.flag_g);
|
||||
|
||||
for filename in &args.arg_file {
|
||||
// Load the preload wasm modules.
|
||||
for filename in &args.flag_preload {
|
||||
let path = Path::new(&filename);
|
||||
match handle_module(&mut context, &args, path) {
|
||||
Ok(()) => {}
|
||||
Err(message) => {
|
||||
let name = path.as_os_str().to_string_lossy();
|
||||
println!("error while processing {}: {}", name, message);
|
||||
println!("error while processing preload {}: {}", name, message);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the main wasm module.
|
||||
let path = Path::new(&args.arg_file);
|
||||
match handle_module(&mut context, &args, path) {
|
||||
Ok(()) => {}
|
||||
Err(message) => {
|
||||
let name = path.as_os_str().to_string_lossy();
|
||||
println!("error while processing main module {}: {}", name, message);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_module(context: &mut Context, args: &Args, path: &Path) -> Result<(), String> {
|
||||
|
||||
BIN
wasi-software-architecture.png
Normal file
BIN
wasi-software-architecture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@@ -13,7 +13,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
gimli = "0.17.0"
|
||||
wasmparser = { version = "0.28.0" }
|
||||
wasmparser = { version = "0.29.0" }
|
||||
cranelift-codegen = "0.30.0"
|
||||
cranelift-entity = "0.30.0"
|
||||
cranelift-wasm = "0.30.0"
|
||||
|
||||
@@ -212,4 +212,12 @@ impl Context {
|
||||
) -> Result<&'instance [u8], ActionError> {
|
||||
inspect_memory(instance, field_name, start, len)
|
||||
}
|
||||
|
||||
/// Return a handle to the global_exports mapping, needed by some modules
|
||||
/// for instantiation.
|
||||
pub fn get_global_exports(
|
||||
&mut self,
|
||||
) -> Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>> {
|
||||
Rc::clone(&mut self.global_exports)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ cranelift-wasm = "0.30.0"
|
||||
wasmtime-environ = { path = "../wasmtime-environ", default-features = false }
|
||||
region = "2.0.0"
|
||||
lazy_static = "1.2.0"
|
||||
libc = { version = "0.2.44", default-features = false }
|
||||
libc = { version = "0.2.48", default-features = false }
|
||||
errno = "0.2.4"
|
||||
memoffset = "0.2.1"
|
||||
memoffset = "0.3.0"
|
||||
cast = { version = "0.2.2", default-features = false }
|
||||
failure = { version = "0.1.3", default-features = false }
|
||||
failure_derive = { version = "0.1.3", default-features = false }
|
||||
@@ -31,7 +31,7 @@ winapi = { version = "0.3.6", features = ["winbase", "memoryapi"] }
|
||||
|
||||
[build-dependencies]
|
||||
cmake = "0.1.35"
|
||||
bindgen = "0.47.1"
|
||||
bindgen = "0.49.0"
|
||||
regex = "1.0.6"
|
||||
|
||||
[features]
|
||||
|
||||
30
wasmtime-wasi/Cargo.toml
Normal file
30
wasmtime-wasi/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "wasmtime-wasi"
|
||||
version = "0.0.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
publish = false
|
||||
description = "WASI API support for Wasmtime"
|
||||
categories = ["wasm"]
|
||||
repository = "https://github.com/CraneStation/wasmtime"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
wasmtime-runtime = { path = "../wasmtime-runtime" }
|
||||
wasmtime-environ = { path = "../wasmtime-environ" }
|
||||
wasmtime-jit = { path = "../wasmtime-jit" }
|
||||
cranelift-codegen = "0.30.0"
|
||||
cranelift-entity = "0.30.0"
|
||||
cranelift-wasm = "0.30.0"
|
||||
target-lexicon = "0.3.0"
|
||||
cast = { version = "0.2.2", default-features = false }
|
||||
log = { version = "0.4.6", default-features = false }
|
||||
libc = "0.2.50"
|
||||
|
||||
[build-dependencies]
|
||||
cmake = "0.1.35"
|
||||
bindgen = "0.49.0"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
travis-ci = { repository = "CraneStation/wasmtime" }
|
||||
220
wasmtime-wasi/LICENSE
Normal file
220
wasmtime-wasi/LICENSE
Normal file
@@ -0,0 +1,220 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
--- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
8
wasmtime-wasi/README.md
Normal file
8
wasmtime-wasi/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
This is the `wasmtime-wasi` crate, which implements the
|
||||
WebAssembly System Interface (WASI) API.
|
||||
|
||||
WASI is greatly inspired by and directly derived from [CloudABI].
|
||||
It differs in that it has aspirations to expand to a greater
|
||||
scope, and to better support the needs of WebAssembly engines.
|
||||
|
||||
[CloudABI]: https://cloudabi.org/
|
||||
36
wasmtime-wasi/build.rs
Normal file
36
wasmtime-wasi/build.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
extern crate bindgen;
|
||||
extern crate cmake;
|
||||
|
||||
use cmake::Config;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let dst = Config::new("sandboxed-system-primitives").build();
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", dst.display());
|
||||
println!("cargo:rustc-link-lib=static=SandboxedSystemPrimitives");
|
||||
|
||||
let bindings_builder = bindgen::Builder::default()
|
||||
.header("sandboxed-system-primitives/include/wasmtime_ssp.h")
|
||||
.header("sandboxed-system-primitives/src/posix.h")
|
||||
.whitelist_function("wasmtime_ssp_.*")
|
||||
.whitelist_function("fd_table_init")
|
||||
.whitelist_function("fd_table_insert_existing")
|
||||
.whitelist_function("fd_prestats_init")
|
||||
.whitelist_function("fd_prestats_insert")
|
||||
.whitelist_function("argv_environ_init")
|
||||
.whitelist_type("__wasi_.*")
|
||||
.whitelist_type("fd_table")
|
||||
.whitelist_type("fd_prestats")
|
||||
.whitelist_type("argv_environ_values")
|
||||
.whitelist_var("__WASI_.*");
|
||||
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
|
||||
bindings_builder
|
||||
.generate()
|
||||
.expect("Unable to generate bindings")
|
||||
.write_to_file(out_path.join("wasmtime_ssp.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
||||
BIN
wasmtime-wasi/js-polyfill/WASI-small.png
Normal file
BIN
wasmtime-wasi/js-polyfill/WASI-small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
18
wasmtime-wasi/js-polyfill/build.sh
Executable file
18
wasmtime-wasi/js-polyfill/build.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
EMCC=emcc
|
||||
|
||||
# TODO: Remove the clang include once Emscripten supports <stdatomic.h>
|
||||
|
||||
"$EMCC" ../sandboxed-system-primitives/src/*.c \
|
||||
-DWASMTIME_SSP_WASI_API \
|
||||
-DWASMTIME_SSP_STATIC_CURFDS \
|
||||
-I../sandboxed-system-primitives/include \
|
||||
-Iclang \
|
||||
--shell-file shell.html \
|
||||
polyfill.c \
|
||||
-s WARN_ON_UNDEFINED_SYMBOLS=0 \
|
||||
-s EXPORTED_FUNCTIONS="['_main', '_handleFiles', '___wasi_args_get', '___wasi_args_sizes_get', '___wasi_clock_res_get', '___wasi_clock_time_get', '___wasi_environ_get', '___wasi_environ_sizes_get', '___wasi_fd_prestat_get', '___wasi_fd_prestat_dir_name', '___wasi_fd_close', '___wasi_fd_datasync', '___wasi_fd_pread', '___wasi_fd_pwrite', '___wasi_fd_read', '___wasi_fd_renumber', '___wasi_fd_seek', '___wasi_fd_tell', '___wasi_fd_fdstat_get', '___wasi_fd_fdstat_set_flags', '___wasi_fd_fdstat_set_rights', '___wasi_fd_sync', '___wasi_fd_write', '___wasi_fd_advise', '___wasi_fd_allocate', '___wasi_path_create_directory', '___wasi_path_link', '___wasi_path_open', '___wasi_fd_readdir', '___wasi_path_readlink', '___wasi_path_rename', '___wasi_fd_filestat_get', '___wasi_fd_filestat_set_times', '___wasi_fd_filestat_set_size', '___wasi_path_filestat_get', '___wasi_path_filestat_set_times', '___wasi_path_symlink', '___wasi_path_unlink_file', '___wasi_path_remove_directory', '___wasi_poll_oneoff', '___wasi_proc_exit', '___wasi_proc_raise', '___wasi_random_get', '___wasi_sched_yield', '___wasi_sock_recv', '___wasi_sock_send', '___wasi_sock_shutdown']" \
|
||||
--pre-js wasi.js \
|
||||
-o polyfill.html
|
||||
190
wasmtime-wasi/js-polyfill/clang/stdatomic.h
Normal file
190
wasmtime-wasi/js-polyfill/clang/stdatomic.h
Normal file
@@ -0,0 +1,190 @@
|
||||
/*===---- stdatomic.h - Standard header for atomic types and operations -----===
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __CLANG_STDATOMIC_H
|
||||
#define __CLANG_STDATOMIC_H
|
||||
|
||||
/* If we're hosted, fall back to the system's stdatomic.h. FreeBSD, for
|
||||
* example, already has a Clang-compatible stdatomic.h header.
|
||||
*/
|
||||
#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>)
|
||||
# include_next <stdatomic.h>
|
||||
#else
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 7.17.1 Introduction */
|
||||
|
||||
#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
|
||||
#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE
|
||||
#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE
|
||||
#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
|
||||
#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
|
||||
#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
|
||||
#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
|
||||
#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
|
||||
|
||||
/* 7.17.2 Initialization */
|
||||
|
||||
#define ATOMIC_VAR_INIT(value) (value)
|
||||
#define atomic_init __c11_atomic_init
|
||||
|
||||
/* 7.17.3 Order and consistency */
|
||||
|
||||
typedef enum memory_order {
|
||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||
memory_order_consume = __ATOMIC_CONSUME,
|
||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||
memory_order_release = __ATOMIC_RELEASE,
|
||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
||||
} memory_order;
|
||||
|
||||
#define kill_dependency(y) (y)
|
||||
|
||||
/* 7.17.4 Fences */
|
||||
|
||||
/* These should be provided by the libc implementation. */
|
||||
void atomic_thread_fence(memory_order);
|
||||
void atomic_signal_fence(memory_order);
|
||||
|
||||
#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
|
||||
#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
|
||||
|
||||
/* 7.17.5 Lock-free property */
|
||||
|
||||
#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj)))
|
||||
|
||||
/* 7.17.6 Atomic integer types */
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef _Atomic(bool) atomic_bool;
|
||||
#else
|
||||
typedef _Atomic(_Bool) atomic_bool;
|
||||
#endif
|
||||
typedef _Atomic(char) atomic_char;
|
||||
typedef _Atomic(signed char) atomic_schar;
|
||||
typedef _Atomic(unsigned char) atomic_uchar;
|
||||
typedef _Atomic(short) atomic_short;
|
||||
typedef _Atomic(unsigned short) atomic_ushort;
|
||||
typedef _Atomic(int) atomic_int;
|
||||
typedef _Atomic(unsigned int) atomic_uint;
|
||||
typedef _Atomic(long) atomic_long;
|
||||
typedef _Atomic(unsigned long) atomic_ulong;
|
||||
typedef _Atomic(long long) atomic_llong;
|
||||
typedef _Atomic(unsigned long long) atomic_ullong;
|
||||
typedef _Atomic(uint_least16_t) atomic_char16_t;
|
||||
typedef _Atomic(uint_least32_t) atomic_char32_t;
|
||||
typedef _Atomic(wchar_t) atomic_wchar_t;
|
||||
typedef _Atomic(int_least8_t) atomic_int_least8_t;
|
||||
typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
|
||||
typedef _Atomic(int_least16_t) atomic_int_least16_t;
|
||||
typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
|
||||
typedef _Atomic(int_least32_t) atomic_int_least32_t;
|
||||
typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
|
||||
typedef _Atomic(int_least64_t) atomic_int_least64_t;
|
||||
typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
|
||||
typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
|
||||
typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
|
||||
typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
|
||||
typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
|
||||
typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
|
||||
typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
|
||||
typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
|
||||
typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
|
||||
typedef _Atomic(intptr_t) atomic_intptr_t;
|
||||
typedef _Atomic(uintptr_t) atomic_uintptr_t;
|
||||
typedef _Atomic(size_t) atomic_size_t;
|
||||
typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||
typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||
|
||||
/* 7.17.7 Operations on atomic types */
|
||||
|
||||
#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST)
|
||||
#define atomic_store_explicit __c11_atomic_store
|
||||
|
||||
#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST)
|
||||
#define atomic_load_explicit __c11_atomic_load
|
||||
|
||||
#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST)
|
||||
#define atomic_exchange_explicit __c11_atomic_exchange
|
||||
|
||||
#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
||||
#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong
|
||||
|
||||
#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
||||
#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak
|
||||
|
||||
#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_add_explicit __c11_atomic_fetch_add
|
||||
|
||||
#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub
|
||||
|
||||
#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_or_explicit __c11_atomic_fetch_or
|
||||
|
||||
#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor
|
||||
|
||||
#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_and_explicit __c11_atomic_fetch_and
|
||||
|
||||
/* 7.17.8 Atomic flag type and operations */
|
||||
|
||||
typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
|
||||
|
||||
#define ATOMIC_FLAG_INIT { 0 }
|
||||
|
||||
/* These should be provided by the libc implementation. */
|
||||
#ifdef __cplusplus
|
||||
bool atomic_flag_test_and_set(volatile atomic_flag *);
|
||||
bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
|
||||
#else
|
||||
_Bool atomic_flag_test_and_set(volatile atomic_flag *);
|
||||
_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
|
||||
#endif
|
||||
void atomic_flag_clear(volatile atomic_flag *);
|
||||
void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order);
|
||||
|
||||
#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST)
|
||||
#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order)
|
||||
|
||||
#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST)
|
||||
#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STDC_HOSTED__ */
|
||||
#endif /* __CLANG_STDATOMIC_H */
|
||||
|
||||
45
wasmtime-wasi/js-polyfill/polyfill.c
Normal file
45
wasmtime-wasi/js-polyfill/polyfill.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <emscripten.h>
|
||||
#include "wasmtime_ssp.h"
|
||||
#include "../src/posix.h"
|
||||
|
||||
static __thread struct fd_table curfds_pointee;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handleFiles(void) {
|
||||
struct fd_table *curfds = &curfds_pointee;
|
||||
|
||||
fd_table_init(curfds);
|
||||
|
||||
// Prepopulate curfds with stdin, stdout, and stderr file descriptors.
|
||||
if (!fd_table_insert_existing(curfds, 0, 0))
|
||||
__builtin_trap();
|
||||
if (!fd_table_insert_existing(curfds, 1, 1))
|
||||
__builtin_trap();
|
||||
if (!fd_table_insert_existing(curfds, 2, 2))
|
||||
__builtin_trap();
|
||||
|
||||
EM_ASM(" \
|
||||
const imports = { wasi_unstable: WASIPolyfill }; \
|
||||
let file = document.getElementById('input').files[0]; \
|
||||
let file_with_mime_type = file.slice(0, file.size, 'application/wasm'); \
|
||||
let response = new Response(file_with_mime_type); \
|
||||
WebAssembly.instantiateStreaming(response, imports) \
|
||||
.then(obj => { \
|
||||
setInstance(obj.instance); \
|
||||
try { \
|
||||
obj.instance.exports._start(); \
|
||||
} catch (e) { \
|
||||
if (e instanceof WASIExit) { \
|
||||
handleWASIExit(e); \
|
||||
} else { \
|
||||
} \
|
||||
} \
|
||||
}) \
|
||||
.catch(error => { \
|
||||
console.log('error! ' + error); \
|
||||
}); \
|
||||
");
|
||||
}
|
||||
88
wasmtime-wasi/js-polyfill/shell.html
Normal file
88
wasmtime-wasi/js-polyfill/shell.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<!doctype html>
|
||||
<!-- This file is derived from src/shell_minimal.html in Emscripten. -->
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>WASI Web Polyfill</title>
|
||||
<style>
|
||||
.wasi { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
|
||||
textarea.wasi { font-family: monospace; width: 80%; }
|
||||
div.wasi { text-align: center; }
|
||||
div.wasi_border { border: 1px solid black; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>WASI</strong></center></figure>
|
||||
<div class="wasi" id="status">Downloading...</div>
|
||||
<div class="wasi">
|
||||
<progress value="0" max="100" id="progress" hidden=1></progress>
|
||||
</div>
|
||||
<img class="wasi" src="WASI-small.png" width="200" height="200" border="0" alt="WASI logo">
|
||||
<input class="wasi" type="file" id="input" onchange="_handleFiles(this.files)">
|
||||
<hr>
|
||||
<textarea class="wasi" id="output" rows="8"></textarea>
|
||||
<script type='text/javascript'>
|
||||
var statusElement = document.getElementById('status');
|
||||
var progressElement = document.getElementById('progress');
|
||||
var spinnerElement = document.getElementById('spinner');
|
||||
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: [],
|
||||
print: (function() {
|
||||
var element = document.getElementById('output');
|
||||
if (element) element.value = ''; // clear browser cache
|
||||
return function(text) {
|
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.log(text);
|
||||
if (element) {
|
||||
element.value += text + "\n";
|
||||
element.scrollTop = element.scrollHeight; // focus on bottom
|
||||
}
|
||||
};
|
||||
})(),
|
||||
printErr: function(text) {
|
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.error(text);
|
||||
},
|
||||
setStatus: function(text) {
|
||||
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
|
||||
if (text === Module.setStatus.last.text) return;
|
||||
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
|
||||
var now = Date.now();
|
||||
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
|
||||
Module.setStatus.last.time = now;
|
||||
Module.setStatus.last.text = text;
|
||||
if (m) {
|
||||
text = m[1];
|
||||
progressElement.value = parseInt(m[2])*100;
|
||||
progressElement.max = parseInt(m[4])*100;
|
||||
progressElement.hidden = false;
|
||||
spinnerElement.hidden = false;
|
||||
} else {
|
||||
progressElement.value = null;
|
||||
progressElement.max = null;
|
||||
progressElement.hidden = true;
|
||||
if (!text) spinnerElement.hidden = true;
|
||||
}
|
||||
statusElement.innerHTML = text;
|
||||
},
|
||||
totalDependencies: 0,
|
||||
monitorRunDependencies: function(left) {
|
||||
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
|
||||
}
|
||||
};
|
||||
Module.setStatus('Downloading...');
|
||||
window.onerror = function() {
|
||||
Module.setStatus('Exception thrown, see JavaScript console');
|
||||
spinnerElement.style.display = 'none';
|
||||
Module.setStatus = function(text) {
|
||||
if (text) Module.printErr('[post-exception status] ' + text);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
{{{ SCRIPT }}}
|
||||
</body>
|
||||
</html>
|
||||
486
wasmtime-wasi/js-polyfill/wasi.js
Normal file
486
wasmtime-wasi/js-polyfill/wasi.js
Normal file
@@ -0,0 +1,486 @@
|
||||
// To implement `proc_exit`, we define a custom exception object
|
||||
// that we can throw to unwind the stack and carry the exit value.
|
||||
function WASIExit(return_value, message, fileName, lineNumber) {
|
||||
let instance = new Error(message, fileName, lineNumber);
|
||||
instance.return_value = return_value;
|
||||
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(instance, WASIExit);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
WASIExit.prototype = Object.create(Error.prototype, {
|
||||
constructor: {
|
||||
value: Error,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.setPrototypeOf) {
|
||||
Object.setPrototypeOf(WASIExit, Error);
|
||||
} else {
|
||||
WASIExit.__proto__ = Error;
|
||||
}
|
||||
|
||||
function handleWASIExit(e) {
|
||||
if (e.return_value != 0) {
|
||||
console.log('program exited with non-zero exit status ' + e.return_value);
|
||||
}
|
||||
}
|
||||
|
||||
// The current guest wasm instance.
|
||||
var currentInstance;
|
||||
|
||||
// There are two heaps in play, the guest heap, which belongs to the WASI-using
|
||||
// program, and the host heap, which belongs to the Emscripten-compiled polyfill
|
||||
// library. The following declare support for the guest heap in a similar manner
|
||||
// to Emscripten's heap.
|
||||
|
||||
var GUEST_HEAP,
|
||||
/** @type {ArrayBuffer} */
|
||||
GUEST_buffer,
|
||||
/** @type {Int8Array} */
|
||||
GUEST_HEAP8,
|
||||
/** @type {Uint8Array} */
|
||||
GUEST_HEAPU8,
|
||||
/** @type {Int16Array} */
|
||||
GUEST_HEAP16,
|
||||
/** @type {Uint16Array} */
|
||||
GUEST_HEAPU16,
|
||||
/** @type {Int32Array} */
|
||||
GUEST_HEAP32,
|
||||
/** @type {Uint32Array} */
|
||||
GUEST_HEAPU32,
|
||||
/** @type {Float32Array} */
|
||||
GUEST_HEAPF32,
|
||||
/** @type {Float64Array} */
|
||||
GUEST_HEAPF64;
|
||||
|
||||
function setInstance(instance) {
|
||||
currentInstance = instance;
|
||||
updateGuestBuffer();
|
||||
}
|
||||
|
||||
/// We call updateGuestBuffer any time the guest's memory may have changed,
|
||||
/// such as when creating a new instance, or after calling _malloc.
|
||||
function updateGuestBuffer() {
|
||||
var buf = currentInstance.exports.memory.buffer;
|
||||
Module['GUEST_buffer'] = GUEST_buffer = buf;
|
||||
Module['GUEST_HEAP8'] = GUEST_HEAP8 = new Int8Array(GUEST_buffer);
|
||||
Module['GUEST_HEAP16'] = GUEST_HEAP16 = new Int16Array(GUEST_buffer);
|
||||
Module['GUEST_HEAP32'] = GUEST_HEAP32 = new Int32Array(GUEST_buffer);
|
||||
Module['GUEST_HEAPU8'] = GUEST_HEAPU8 = new Uint8Array(GUEST_buffer);
|
||||
Module['GUEST_HEAPU16'] = GUEST_HEAPU16 = new Uint16Array(GUEST_buffer);
|
||||
Module['GUEST_HEAPU32'] = GUEST_HEAPU32 = new Uint32Array(GUEST_buffer);
|
||||
Module['GUEST_HEAPF32'] = GUEST_HEAPF32 = new Float32Array(GUEST_buffer);
|
||||
Module['GUEST_HEAPF64'] = GUEST_HEAPF64 = new Float64Array(GUEST_buffer);
|
||||
}
|
||||
|
||||
function copyin_bytes(src, len) {
|
||||
let dst = _malloc(len);
|
||||
updateGuestBuffer();
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
HEAP8[dst + i] = GUEST_HEAP8[src + i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
function copyout_bytes(dst, src, len) {
|
||||
updateGuestBuffer();
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
GUEST_HEAP8[dst + i] = HEAP8[src + i];
|
||||
}
|
||||
_free(src);
|
||||
}
|
||||
|
||||
function copyout_i32(dst, src) {
|
||||
updateGuestBuffer();
|
||||
|
||||
GUEST_HEAP32[dst>>2] = HEAP32[src>>2];
|
||||
_free(src);
|
||||
}
|
||||
|
||||
function copyout_i64(dst, src) {
|
||||
updateGuestBuffer();
|
||||
|
||||
GUEST_HEAP32[dst>>2] = HEAP32[src>>2];
|
||||
GUEST_HEAP32[(dst + 4)>>2] = HEAP32[(src + 4)>>2];
|
||||
_free(src);
|
||||
}
|
||||
|
||||
function translate_ciovs(iovs, iovs_len) {
|
||||
host_iovs = _malloc(8 * iovs_len);
|
||||
updateGuestBuffer();
|
||||
|
||||
for (let i = 0; i < iovs_len; ++i) {
|
||||
let ptr = GUEST_HEAP32[(iovs + i * 8 + 0) >> 2];
|
||||
let len = GUEST_HEAP32[(iovs + i * 8 + 4) >> 2];
|
||||
let buf = copyin_bytes(ptr, len);
|
||||
HEAP32[(host_iovs + i * 8 + 0)>>2] = buf;
|
||||
HEAP32[(host_iovs + i * 8 + 4)>>2] = len;
|
||||
}
|
||||
return host_iovs;
|
||||
}
|
||||
|
||||
function free_ciovs(host_iovs, iovs_len) {
|
||||
for (let i = 0; i < iovs_len; ++i) {
|
||||
let buf = HEAP32[(host_iovs + i * 8 + 0) >> 2];
|
||||
_free(buf);
|
||||
}
|
||||
_free(host_iovs);
|
||||
}
|
||||
|
||||
function translate_iovs(iovs, iovs_len) {
|
||||
host_iovs = _malloc(8 * iovs_len);
|
||||
updateGuestBuffer();
|
||||
|
||||
for (let i = 0; i < iovs_len; ++i) {
|
||||
let len = GUEST_HEAP32[(iovs + i * 8 + 4) >> 2];
|
||||
let buf = _malloc(len);
|
||||
updateGuestBuffer();
|
||||
HEAP32[(host_iovs + i * 8 + 0)>>2] = buf;
|
||||
HEAP32[(host_iovs + i * 8 + 4)>>2] = len;
|
||||
}
|
||||
return host_iovs;
|
||||
}
|
||||
|
||||
function free_iovs(host_iovs, iovs_len, iovs) {
|
||||
updateGuestBuffer();
|
||||
for (let i = 0; i < iovs_len; ++i) {
|
||||
let buf = HEAP32[(host_iovs + i * 8 + 0) >> 2];
|
||||
let len = HEAP32[(host_iovs + i * 8 + 4) >> 2];
|
||||
let ptr = GUEST_HEAP32[(host_iovs + i * 8 + 0) >> 2];
|
||||
copyout_bytes(ptr, buf, len);
|
||||
}
|
||||
_free(host_iovs);
|
||||
}
|
||||
|
||||
var WASIPolyfill = {
|
||||
|
||||
args_get: function(argv, argv_buf) {
|
||||
return 0;
|
||||
},
|
||||
|
||||
args_sizes_get: function(argc, argv_buf_size) {
|
||||
updateGuestBuffer();
|
||||
|
||||
// TODO: Implement command-line arguments.
|
||||
GUEST_HEAP32[(argc) >> 2] = 0;
|
||||
GUEST_HEAP32[(argv_buf_size) >> 2] = 0;
|
||||
return 0;
|
||||
},
|
||||
|
||||
clock_res_get: function(clock_id, resolution) {
|
||||
let host_resolution = _malloc(8);
|
||||
let ret = ___wasi_clock_res_get(clock_id, host_resolution);
|
||||
copyout_i64(resolution, host_resolution);
|
||||
return ret;
|
||||
},
|
||||
|
||||
clock_time_get: function(clock_id, precision, time) {
|
||||
let host_time = _malloc(8);
|
||||
let ret = ___wasi_clock_time_get(clock_id, precision, host_time);
|
||||
copyout_i64(time, host_time);
|
||||
return ret;
|
||||
},
|
||||
|
||||
environ_get: function(environ, environ_buf) {
|
||||
return 0;
|
||||
},
|
||||
|
||||
environ_sizes_get: function(environ_size, environ_buf_size) {
|
||||
updateGuestBuffer();
|
||||
|
||||
// TODO: Implement environment variables.
|
||||
GUEST_HEAP32[(environ_size) >> 2] = 0;
|
||||
GUEST_HEAP32[(environ_buf_size) >> 2] = 0;
|
||||
return 0;
|
||||
},
|
||||
|
||||
fd_prestat_get: function(fd, buf) {
|
||||
let host_buf = _malloc(8); // sizeof __wasi_prestat_t
|
||||
let ret = ___wasi_fd_prestat_get(fd, host_buf);
|
||||
copyout_bytes(buf, host_buf, 8);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_prestat_dir_name: function(fd, path, path_len) {
|
||||
let host_buf = _malloc(path_len);
|
||||
let ret = ___wasi_fd_prestat_get(fd, host_buf, path_len);
|
||||
copyout_bytes(buf, host_buf, path_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_close: function(fd) {
|
||||
return ___wasi_fd_close(fd);
|
||||
},
|
||||
|
||||
fd_datasync: function(fd) {
|
||||
return ___wasi_fd_datasync(fd);
|
||||
},
|
||||
|
||||
fd_pread: function(fd, iovs, iovs_len, offset, nread) {
|
||||
let host_iovs = translate_iovs(iovs, iovs_len);
|
||||
let host_nread = _malloc(4);
|
||||
let ret = ___wasi_fd_pread(fd, host_iovs, iovs_len, offset, host_nread);
|
||||
copyout_i32(nread, host_nread);
|
||||
free_iovs(host_iovs, iovs_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_pwrite: function(fd, iovs, iovs_len, offset, nwritten) {
|
||||
let host_iovs = translate_ciovs(iovs, iovs_len);
|
||||
let host_nwritten = _malloc(4);
|
||||
let ret = ___wasi_fd_pwrite(fd, host_iovs, iovs_len, offset, host_nwritten);
|
||||
copyout_i32(nwritten, host_nwritten);
|
||||
free_ciovs(host_iovs, iovs_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_read: function(fd, iovs, iovs_len, nread) {
|
||||
let host_iovs = translate_iovs(iovs, iovs_len);
|
||||
let host_nread = _malloc(4);
|
||||
let ret = ___wasi_fd_read(fd, host_iovs, iovs_len, host_nread);
|
||||
copyout_i32(nread, host_nread);
|
||||
free_iovs(host_iovs, iovs_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_renumber: function(from, to) {
|
||||
return ___wasi_fd_renumber(from, to);
|
||||
},
|
||||
|
||||
fd_seek: function(fd, offset, whence, newoffset) {
|
||||
let host_newoffset = _malloc(8);
|
||||
let ret = ___wasi_fd_seek(fd, offset, whence, host_newoffset);
|
||||
copyout_i64(newoffset, host_newoffset);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_tell: function(fd, newoffset) {
|
||||
let host_newoffset = _malloc(8);
|
||||
let ret = ___wasi_fd_seek(fd, host_newoffset);
|
||||
copyout_i64(newoffset, host_newoffset);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_fdstat_get: function(fd, buf) {
|
||||
let host_buf = _malloc(24); // sizeof __wasi_fdstat_t
|
||||
let ret = ___wasi_fd_fdstat_get(fd, host_buf);
|
||||
copyout_bytes(buf, host_buf, 24);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_fdstat_set_flags: function(fd, flags) {
|
||||
return ___wasi_fd_fdstat_set_flags(fd, flags);
|
||||
},
|
||||
|
||||
fd_fdstat_set_rights: function(fd, fs_rights_base, fs_rights_inheriting) {
|
||||
return ___wasi_fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting);
|
||||
},
|
||||
|
||||
fd_sync: function(fd) {
|
||||
return ___wasi_fd_sync(fd);
|
||||
},
|
||||
|
||||
fd_write: function(fd, iovs, iovs_len, nwritten) {
|
||||
let host_iovs = translate_ciovs(iovs, iovs_len);
|
||||
let host_nwritten = _malloc(4);
|
||||
let ret = ___wasi_fd_write(fd, host_iovs, iovs_len, host_nwritten);
|
||||
copyout_i32(nwritten, host_nwritten);
|
||||
free_ciovs(host_iovs, iovs_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_advise: function(fd, offset, len, advice) {
|
||||
return ___wasi_fd_advise(fd, offset, len, advice);
|
||||
},
|
||||
|
||||
fd_allocate: function(fd, offset, len) {
|
||||
return ___wasi_fd_allocate(fd, offset, len);
|
||||
},
|
||||
|
||||
path_create_directory: function(fd, path, path_len) {
|
||||
let host_path = copyin_bytes(path, path_len);
|
||||
let ret = ___wasi_path_create_directory(fd, host_path, path_len);
|
||||
_free(host_path);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_link: function(fd0, path0, path_len0, fd1, path1, path_len1) {
|
||||
let host_path0 = copyin_bytes(path0, path_len0);
|
||||
let host_path1 = copyin_bytes(path1, path_len1);
|
||||
let ret = ___wasi_path_link(fd, host_path0, path_len0, fd1, host_path1, path1_len);
|
||||
_free(host_path1);
|
||||
_free(host_path0);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_open: function(dirfd, dirflags, path, path_len, oflags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) {
|
||||
let host_path = copyin_bytes(path, path_len);
|
||||
let host_fd = _malloc(4);
|
||||
let ret = ___wasi_path_open(dirfd, dirflags, host_path, path_len, oflags, fs_rights_base, fs_rights_inheriting, fs_flags, host_fd);
|
||||
copyout_i32(fd, host_fd);
|
||||
_free(host_path);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_readdir: function(fd, buf, buf_len, cookie, buf_used) {
|
||||
let host_buf = _malloc(buf_len);
|
||||
let host_buf_used = _malloc(4);
|
||||
let ret = ___wasi_fd_readdir(fd, buf, buf_len, cookie, host_buf_used);
|
||||
copyout_i32(buf_used, host_buf_used);
|
||||
copyout_bytes(buf, host_buf, buf_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_readlink: function(fd, path, path_len, buf, buf_len, buf_used) {
|
||||
let host_path = copyin_bytes(path, path_len);
|
||||
let host_buf = _malloc(buf_len);
|
||||
let host_buf_used = _malloc(4);
|
||||
let ret = ___wasi_path_readlink(fd, path, path_len, buf, buf_len, host_buf_used);
|
||||
copyout_i32(buf_used, host_buf_used);
|
||||
copyout_bytes(buf, host_buf, buf_len);
|
||||
_free(host_path);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_rename: function(fd0, path0, path_len0, fd1, path1, path_len1) {
|
||||
let host_path0 = copyin_bytes(path0, path_len0);
|
||||
let host_path1 = copyin_bytes(path1, path_len1);
|
||||
let ret = ___wasi_path_rename(fd, host_path0, path_len0, fd1, host_path1, path1_len);
|
||||
_free(host_path1);
|
||||
_free(host_path0);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_filestat_get: function(fd, buf) {
|
||||
let host_buf = _malloc(56); // sizeof __wasi_filestat_t
|
||||
let ret = ___wasi_fd_filestat_get(host_buf);
|
||||
copyout_bytes(buf, host_buf, 56);
|
||||
return ret;
|
||||
},
|
||||
|
||||
fd_filestat_set_size: function(fd, size) {
|
||||
return ___wasi_fd_filestat_set_size(fd, size);
|
||||
},
|
||||
|
||||
fd_filestat_set_times: function(fd, st_atim, st_mtim, fstflags) {
|
||||
return ___wasi_fd_filestat_set_times(fd, st_atim, st_mtim, fstflags);
|
||||
},
|
||||
|
||||
path_filestat_get: function(fd, path, path_len, buf) {
|
||||
let host_path = copyin_bytes(path, path_len);
|
||||
let host_buf = _malloc(56); // sizeof __wasi_filestat_t
|
||||
let ret = ___wasi_path_filestat_get(fd, host_path, path_len, host_buf);
|
||||
copyout_bytes(buf, host_buf, 56);
|
||||
_free(host_path);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_filestat_set_times: function(fd, path, path_len, st_atim, st_mtim, flags) {
|
||||
let host_path = copyin_bytes(path, path_len);
|
||||
let ret = ___wasi_path_filestat_set_times(fd, host_path, st_atim, st_mtim, fstflags);
|
||||
_free(host_path);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_symlink: function(path0, path_len0, fd, path1, path_len1) {
|
||||
let host_path0 = copyin_bytes(path0, path0_len);
|
||||
let host_path1 = copyin_bytes(path1, path1_len);
|
||||
let ret = ___wasi_path_symlink(host_path0, path_len0, fd, host_path1, path_len1);
|
||||
_free(host_path1);
|
||||
_free(host_path0);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_unlink_file: function(fd, path, path_len, flags) {
|
||||
let host_path = copyin_bytes(path, path_len);
|
||||
let ret = ___wasi_path_unlink_file(fd, host_path, path_len, flags);
|
||||
_free(host_path);
|
||||
return ret;
|
||||
},
|
||||
|
||||
path_remove_directory: function(fd, path, path_len, flags) {
|
||||
let host_path = copyin_bytes(path, path_len);
|
||||
let ret = ___wasi_path_remove_directory(fd, host_path, path_len, flags);
|
||||
_free(host_path);
|
||||
return ret;
|
||||
},
|
||||
|
||||
poll_oneoff: function(in_, out, nsubscriptions, nevents) {
|
||||
let host_in = copyin_bytes(in_, nsubscriptions * 56); // sizeof __wasi_subscription_t
|
||||
let host_out = _malloc(nsubscriptions * 32); // sizeof __wasi_event_t
|
||||
let host_nevents = _malloc(4);
|
||||
let ret = ___wasi_poll_oneoff(host_in, host_out, host_nevents);
|
||||
copyout_bytes(out, host_out, nsubscriptions * 32);
|
||||
copyout_i32(nevents, host_nevents);
|
||||
_free(host_in);
|
||||
return ret;
|
||||
},
|
||||
|
||||
proc_exit: function(rval) {
|
||||
let message;
|
||||
if (rval == 0) {
|
||||
message = "success";
|
||||
} else {
|
||||
message = "error code " + rval;
|
||||
}
|
||||
throw new WASIExit(rval, message);
|
||||
},
|
||||
|
||||
proc_raise: function(sig) {
|
||||
if (sig == 18 || // SIGSTOP
|
||||
sig == 19 || // SIGTSTP
|
||||
sig == 20 || // SIGTTIN
|
||||
sig == 21 || // SIGTTOU
|
||||
sig == 22 || // SIGURG
|
||||
sig == 16 || // SIGCHLD
|
||||
sig == 13) // SIGPIPE
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
let message = "raised signal " + sig;
|
||||
throw new WASIExit(128 + sig, message);
|
||||
},
|
||||
|
||||
random_get: function(buf, buf_len) {
|
||||
let host_buf = _malloc(buf_len);
|
||||
let ret = __wasi_random_get(host_buf, buf_len);
|
||||
copyout_bytes(buf, host_buf, buf_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
sched_yield: function() {
|
||||
return __wasi_sched_yield();
|
||||
},
|
||||
|
||||
sock_recv: function(sock, ri_data, ri_data_len, ri_flags, ro_datalen, ro_flags) {
|
||||
let host_ri_data = translate_iovs(ri_data, ri_data_len);
|
||||
let host_ro_datalen = _malloc(4);
|
||||
let ret = ___wasi_sock_recv(sock, host_ri_data, ri_data_len, ri_flags, host_ro_data, ro_flags);
|
||||
copyout_i32(ro_datalen, host_ro_datalen);
|
||||
free_iovs(host_ri_data, ri_data_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
sock_send: function(sock, si_data, si_data_len, si_flags, so_datalen) {
|
||||
let host_si_data = translate_ciovs(si_data, si_data_len);
|
||||
let host_so_datalen = _malloc(4);
|
||||
let ret = ___wasi_sock_send(sock, host_si_data, si_data_len, si_flags, host_so_datalen);
|
||||
copyout_i32(so_datalen, host_so_datalen);
|
||||
free_ciovs(host_si_data, si_data_len);
|
||||
return ret;
|
||||
},
|
||||
|
||||
sock_shutdown: function(sock, how) {
|
||||
return __wasi_sock_shutdown(sock, how);
|
||||
}
|
||||
|
||||
};
|
||||
8
wasmtime-wasi/sandboxed-system-primitives/CMakeLists.txt
Normal file
8
wasmtime-wasi/sandboxed-system-primitives/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(SandboxedSystemPrimitives C)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
add_library(SandboxedSystemPrimitives STATIC src/posix.c src/random.c src/str.c)
|
||||
|
||||
install(TARGETS SandboxedSystemPrimitives DESTINATION .)
|
||||
7
wasmtime-wasi/sandboxed-system-primitives/LICENSE
Normal file
7
wasmtime-wasi/sandboxed-system-primitives/LICENSE
Normal file
@@ -0,0 +1,7 @@
|
||||
Please see the LICENSE file in each top-level directory for the terms applicable to that directory and its relative sub-directories.
|
||||
|
||||
The relevant directories and licenses are:
|
||||
|
||||
src/ - BSD-2-Clause; see src/LICENSE for details
|
||||
include/ - CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
polyfill/clang/ - MIT; see the header of polyfill/clang/stdatomic.h for details
|
||||
9
wasmtime-wasi/sandboxed-system-primitives/README.md
Normal file
9
wasmtime-wasi/sandboxed-system-primitives/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
This repository contains adapted forms of the CloudABI project's "libemulator"
|
||||
library, which includes implementations the CloudABI system calls using
|
||||
standard native platform support. See the README.md and LICENSE files in
|
||||
the individual subdirectories for details.
|
||||
|
||||
src/ - cloudabi-utils' libemulator; see src/README.md for details
|
||||
include/ - wasi headers
|
||||
|
||||
This is currently an experimental prototype.
|
||||
121
wasmtime-wasi/sandboxed-system-primitives/include/LICENSE
Normal file
121
wasmtime-wasi/sandboxed-system-primitives/include/LICENSE
Normal file
@@ -0,0 +1,121 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
865
wasmtime-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h
Normal file
865
wasmtime-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h
Normal file
@@ -0,0 +1,865 @@
|
||||
/*
|
||||
* Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
* See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
*
|
||||
* This file declares an interface similar to WASI, but augmented to expose
|
||||
* some implementation details such as the curfds arguments that we pass
|
||||
* around to avoid storing them in TLS.
|
||||
*/
|
||||
|
||||
#ifndef WASMTIME_SSP_H
|
||||
#define WASMTIME_SSP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
_Static_assert(_Alignof(int8_t) == 1, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(uint8_t) == 1, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(int16_t) == 2, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(uint16_t) == 2, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(int32_t) == 4, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(uint32_t) == 4, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout");
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint8_t __wasi_advice_t;
|
||||
#define __WASI_ADVICE_NORMAL (0)
|
||||
#define __WASI_ADVICE_SEQUENTIAL (1)
|
||||
#define __WASI_ADVICE_RANDOM (2)
|
||||
#define __WASI_ADVICE_WILLNEED (3)
|
||||
#define __WASI_ADVICE_DONTNEED (4)
|
||||
#define __WASI_ADVICE_NOREUSE (5)
|
||||
|
||||
typedef uint32_t __wasi_clockid_t;
|
||||
#define __WASI_CLOCK_REALTIME (0)
|
||||
#define __WASI_CLOCK_MONOTONIC (1)
|
||||
#define __WASI_CLOCK_PROCESS_CPUTIME_ID (2)
|
||||
#define __WASI_CLOCK_THREAD_CPUTIME_ID (3)
|
||||
|
||||
typedef uint64_t __wasi_device_t;
|
||||
|
||||
typedef uint64_t __wasi_dircookie_t;
|
||||
#define __WASI_DIRCOOKIE_START (0)
|
||||
|
||||
typedef uint16_t __wasi_errno_t;
|
||||
#define __WASI_ESUCCESS (0)
|
||||
#define __WASI_E2BIG (1)
|
||||
#define __WASI_EACCES (2)
|
||||
#define __WASI_EADDRINUSE (3)
|
||||
#define __WASI_EADDRNOTAVAIL (4)
|
||||
#define __WASI_EAFNOSUPPORT (5)
|
||||
#define __WASI_EAGAIN (6)
|
||||
#define __WASI_EALREADY (7)
|
||||
#define __WASI_EBADF (8)
|
||||
#define __WASI_EBADMSG (9)
|
||||
#define __WASI_EBUSY (10)
|
||||
#define __WASI_ECANCELED (11)
|
||||
#define __WASI_ECHILD (12)
|
||||
#define __WASI_ECONNABORTED (13)
|
||||
#define __WASI_ECONNREFUSED (14)
|
||||
#define __WASI_ECONNRESET (15)
|
||||
#define __WASI_EDEADLK (16)
|
||||
#define __WASI_EDESTADDRREQ (17)
|
||||
#define __WASI_EDOM (18)
|
||||
#define __WASI_EDQUOT (19)
|
||||
#define __WASI_EEXIST (20)
|
||||
#define __WASI_EFAULT (21)
|
||||
#define __WASI_EFBIG (22)
|
||||
#define __WASI_EHOSTUNREACH (23)
|
||||
#define __WASI_EIDRM (24)
|
||||
#define __WASI_EILSEQ (25)
|
||||
#define __WASI_EINPROGRESS (26)
|
||||
#define __WASI_EINTR (27)
|
||||
#define __WASI_EINVAL (28)
|
||||
#define __WASI_EIO (29)
|
||||
#define __WASI_EISCONN (30)
|
||||
#define __WASI_EISDIR (31)
|
||||
#define __WASI_ELOOP (32)
|
||||
#define __WASI_EMFILE (33)
|
||||
#define __WASI_EMLINK (34)
|
||||
#define __WASI_EMSGSIZE (35)
|
||||
#define __WASI_EMULTIHOP (36)
|
||||
#define __WASI_ENAMETOOLONG (37)
|
||||
#define __WASI_ENETDOWN (38)
|
||||
#define __WASI_ENETRESET (39)
|
||||
#define __WASI_ENETUNREACH (40)
|
||||
#define __WASI_ENFILE (41)
|
||||
#define __WASI_ENOBUFS (42)
|
||||
#define __WASI_ENODEV (43)
|
||||
#define __WASI_ENOENT (44)
|
||||
#define __WASI_ENOEXEC (45)
|
||||
#define __WASI_ENOLCK (46)
|
||||
#define __WASI_ENOLINK (47)
|
||||
#define __WASI_ENOMEM (48)
|
||||
#define __WASI_ENOMSG (49)
|
||||
#define __WASI_ENOPROTOOPT (50)
|
||||
#define __WASI_ENOSPC (51)
|
||||
#define __WASI_ENOSYS (52)
|
||||
#define __WASI_ENOTCONN (53)
|
||||
#define __WASI_ENOTDIR (54)
|
||||
#define __WASI_ENOTEMPTY (55)
|
||||
#define __WASI_ENOTRECOVERABLE (56)
|
||||
#define __WASI_ENOTSOCK (57)
|
||||
#define __WASI_ENOTSUP (58)
|
||||
#define __WASI_ENOTTY (59)
|
||||
#define __WASI_ENXIO (60)
|
||||
#define __WASI_EOVERFLOW (61)
|
||||
#define __WASI_EOWNERDEAD (62)
|
||||
#define __WASI_EPERM (63)
|
||||
#define __WASI_EPIPE (64)
|
||||
#define __WASI_EPROTO (65)
|
||||
#define __WASI_EPROTONOSUPPORT (66)
|
||||
#define __WASI_EPROTOTYPE (67)
|
||||
#define __WASI_ERANGE (68)
|
||||
#define __WASI_EROFS (69)
|
||||
#define __WASI_ESPIPE (70)
|
||||
#define __WASI_ESRCH (71)
|
||||
#define __WASI_ESTALE (72)
|
||||
#define __WASI_ETIMEDOUT (73)
|
||||
#define __WASI_ETXTBSY (74)
|
||||
#define __WASI_EXDEV (75)
|
||||
#define __WASI_ENOTCAPABLE (76)
|
||||
|
||||
typedef uint16_t __wasi_eventrwflags_t;
|
||||
#define __WASI_EVENT_FD_READWRITE_HANGUP (0x0001)
|
||||
|
||||
typedef uint8_t __wasi_eventtype_t;
|
||||
#define __WASI_EVENTTYPE_CLOCK (0)
|
||||
#define __WASI_EVENTTYPE_FD_READ (1)
|
||||
#define __WASI_EVENTTYPE_FD_WRITE (2)
|
||||
|
||||
typedef uint32_t __wasi_exitcode_t;
|
||||
|
||||
typedef uint32_t __wasi_fd_t;
|
||||
|
||||
typedef uint16_t __wasi_fdflags_t;
|
||||
#define __WASI_FDFLAG_APPEND (0x0001)
|
||||
#define __WASI_FDFLAG_DSYNC (0x0002)
|
||||
#define __WASI_FDFLAG_NONBLOCK (0x0004)
|
||||
#define __WASI_FDFLAG_RSYNC (0x0008)
|
||||
#define __WASI_FDFLAG_SYNC (0x0010)
|
||||
|
||||
typedef int64_t __wasi_filedelta_t;
|
||||
|
||||
typedef uint64_t __wasi_filesize_t;
|
||||
|
||||
typedef uint8_t __wasi_filetype_t;
|
||||
#define __WASI_FILETYPE_UNKNOWN (0)
|
||||
#define __WASI_FILETYPE_BLOCK_DEVICE (1)
|
||||
#define __WASI_FILETYPE_CHARACTER_DEVICE (2)
|
||||
#define __WASI_FILETYPE_DIRECTORY (3)
|
||||
#define __WASI_FILETYPE_REGULAR_FILE (4)
|
||||
#define __WASI_FILETYPE_SOCKET_DGRAM (5)
|
||||
#define __WASI_FILETYPE_SOCKET_STREAM (6)
|
||||
#define __WASI_FILETYPE_SYMBOLIC_LINK (7)
|
||||
|
||||
typedef uint16_t __wasi_fstflags_t;
|
||||
#define __WASI_FILESTAT_SET_ATIM (0x0001)
|
||||
#define __WASI_FILESTAT_SET_ATIM_NOW (0x0002)
|
||||
#define __WASI_FILESTAT_SET_MTIM (0x0004)
|
||||
#define __WASI_FILESTAT_SET_MTIM_NOW (0x0008)
|
||||
|
||||
typedef uint64_t __wasi_inode_t;
|
||||
|
||||
typedef uint32_t __wasi_linkcount_t;
|
||||
|
||||
typedef uint32_t __wasi_lookupflags_t;
|
||||
#define __WASI_LOOKUP_SYMLINK_FOLLOW (0x00000001)
|
||||
|
||||
typedef uint16_t __wasi_oflags_t;
|
||||
#define __WASI_O_CREAT (0x0001)
|
||||
#define __WASI_O_DIRECTORY (0x0002)
|
||||
#define __WASI_O_EXCL (0x0004)
|
||||
#define __WASI_O_TRUNC (0x0008)
|
||||
|
||||
typedef uint16_t __wasi_riflags_t;
|
||||
#define __WASI_SOCK_RECV_PEEK (0x0001)
|
||||
#define __WASI_SOCK_RECV_WAITALL (0x0002)
|
||||
|
||||
typedef uint64_t __wasi_rights_t;
|
||||
#define __WASI_RIGHT_FD_DATASYNC (0x0000000000000001)
|
||||
#define __WASI_RIGHT_FD_READ (0x0000000000000002)
|
||||
#define __WASI_RIGHT_FD_SEEK (0x0000000000000004)
|
||||
#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS (0x0000000000000008)
|
||||
#define __WASI_RIGHT_FD_SYNC (0x0000000000000010)
|
||||
#define __WASI_RIGHT_FD_TELL (0x0000000000000020)
|
||||
#define __WASI_RIGHT_FD_WRITE (0x0000000000000040)
|
||||
#define __WASI_RIGHT_FD_ADVISE (0x0000000000000080)
|
||||
#define __WASI_RIGHT_FD_ALLOCATE (0x0000000000000100)
|
||||
#define __WASI_RIGHT_PATH_CREATE_DIRECTORY (0x0000000000000200)
|
||||
#define __WASI_RIGHT_PATH_CREATE_FILE (0x0000000000000400)
|
||||
#define __WASI_RIGHT_PATH_LINK_SOURCE (0x0000000000000800)
|
||||
#define __WASI_RIGHT_PATH_LINK_TARGET (0x0000000000001000)
|
||||
#define __WASI_RIGHT_PATH_OPEN (0x0000000000002000)
|
||||
#define __WASI_RIGHT_FD_READDIR (0x0000000000004000)
|
||||
#define __WASI_RIGHT_PATH_READLINK (0x0000000000008000)
|
||||
#define __WASI_RIGHT_PATH_RENAME_SOURCE (0x0000000000010000)
|
||||
#define __WASI_RIGHT_PATH_RENAME_TARGET (0x0000000000020000)
|
||||
#define __WASI_RIGHT_PATH_FILESTAT_GET (0x0000000000040000)
|
||||
#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE (0x0000000000080000)
|
||||
#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES (0x0000000000100000)
|
||||
#define __WASI_RIGHT_FD_FILESTAT_GET (0x0000000000200000)
|
||||
#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE (0x0000000000400000)
|
||||
#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES (0x0000000000800000)
|
||||
#define __WASI_RIGHT_PATH_SYMLINK (0x0000000001000000)
|
||||
#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY (0x0000000002000000)
|
||||
#define __WASI_RIGHT_PATH_UNLINK_FILE (0x0000000004000000)
|
||||
#define __WASI_RIGHT_POLL_FD_READWRITE (0x0000000008000000)
|
||||
#define __WASI_RIGHT_SOCK_SHUTDOWN (0x0000000010000000)
|
||||
|
||||
typedef uint16_t __wasi_roflags_t;
|
||||
#define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001)
|
||||
|
||||
typedef uint8_t __wasi_sdflags_t;
|
||||
#define __WASI_SHUT_RD (0x01)
|
||||
#define __WASI_SHUT_WR (0x02)
|
||||
|
||||
typedef uint16_t __wasi_siflags_t;
|
||||
|
||||
typedef uint8_t __wasi_signal_t;
|
||||
// 0 is reserved; POSIX has special semantics for kill(pid, 0).
|
||||
#define __WASI_SIGHUP (1)
|
||||
#define __WASI_SIGINT (2)
|
||||
#define __WASI_SIGQUIT (3)
|
||||
#define __WASI_SIGILL (4)
|
||||
#define __WASI_SIGTRAP (5)
|
||||
#define __WASI_SIGABRT (6)
|
||||
#define __WASI_SIGBUS (7)
|
||||
#define __WASI_SIGFPE (8)
|
||||
#define __WASI_SIGKILL (9)
|
||||
#define __WASI_SIGUSR1 (10)
|
||||
#define __WASI_SIGSEGV (11)
|
||||
#define __WASI_SIGUSR2 (12)
|
||||
#define __WASI_SIGPIPE (13)
|
||||
#define __WASI_SIGALRM (14)
|
||||
#define __WASI_SIGTERM (15)
|
||||
#define __WASI_SIGCHLD (16)
|
||||
#define __WASI_SIGCONT (17)
|
||||
#define __WASI_SIGSTOP (18)
|
||||
#define __WASI_SIGTSTP (19)
|
||||
#define __WASI_SIGTTIN (20)
|
||||
#define __WASI_SIGTTOU (21)
|
||||
#define __WASI_SIGURG (22)
|
||||
#define __WASI_SIGXCPU (23)
|
||||
#define __WASI_SIGXFSZ (24)
|
||||
#define __WASI_SIGVTALRM (25)
|
||||
#define __WASI_SIGPROF (26)
|
||||
#define __WASI_SIGWINCH (27)
|
||||
#define __WASI_SIGPOLL (28)
|
||||
#define __WASI_SIGPWR (29)
|
||||
#define __WASI_SIGSYS (30)
|
||||
|
||||
typedef uint16_t __wasi_subclockflags_t;
|
||||
#define __WASI_SUBSCRIPTION_CLOCK_ABSTIME (0x0001)
|
||||
|
||||
typedef uint64_t __wasi_timestamp_t;
|
||||
|
||||
typedef uint64_t __wasi_userdata_t;
|
||||
|
||||
typedef uint8_t __wasi_whence_t;
|
||||
#define __WASI_WHENCE_CUR (0)
|
||||
#define __WASI_WHENCE_END (1)
|
||||
#define __WASI_WHENCE_SET (2)
|
||||
|
||||
typedef uint8_t __wasi_preopentype_t;
|
||||
#define __WASI_PREOPENTYPE_DIR (0)
|
||||
|
||||
struct fd_table;
|
||||
struct fd_prestats;
|
||||
struct argv_environ_values;
|
||||
|
||||
typedef struct __wasi_dirent_t {
|
||||
__wasi_dircookie_t d_next;
|
||||
__wasi_inode_t d_ino;
|
||||
uint32_t d_namlen;
|
||||
__wasi_filetype_t d_type;
|
||||
} __wasi_dirent_t;
|
||||
_Static_assert(offsetof(__wasi_dirent_t, d_next) == 0, "non-wasi data layout");
|
||||
_Static_assert(offsetof(__wasi_dirent_t, d_ino) == 8, "non-wasi data layout");
|
||||
_Static_assert(offsetof(__wasi_dirent_t, d_namlen) == 16, "non-wasi data layout");
|
||||
_Static_assert(offsetof(__wasi_dirent_t, d_type) == 20, "non-wasi data layout");
|
||||
_Static_assert(sizeof(__wasi_dirent_t) == 24, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(__wasi_dirent_t) == 8, "non-wasi data layout");
|
||||
|
||||
typedef struct __wasi_event_t {
|
||||
__wasi_userdata_t userdata;
|
||||
__wasi_errno_t error;
|
||||
__wasi_eventtype_t type;
|
||||
union __wasi_event_u {
|
||||
struct __wasi_event_u_fd_readwrite_t {
|
||||
__wasi_filesize_t nbytes;
|
||||
__wasi_eventrwflags_t flags;
|
||||
} fd_readwrite;
|
||||
} u;
|
||||
} __wasi_event_t;
|
||||
_Static_assert(offsetof(__wasi_event_t, userdata) == 0, "non-wasi data layout");
|
||||
_Static_assert(offsetof(__wasi_event_t, error) == 8, "non-wasi data layout");
|
||||
_Static_assert(offsetof(__wasi_event_t, type) == 10, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_event_t, u.fd_readwrite.nbytes) == 16, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_event_t, u.fd_readwrite.flags) == 24, "non-wasi data layout");
|
||||
_Static_assert(sizeof(__wasi_event_t) == 32, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(__wasi_event_t) == 8, "non-wasi data layout");
|
||||
|
||||
typedef struct __wasi_prestat_t {
|
||||
__wasi_preopentype_t pr_type;
|
||||
union __wasi_prestat_u {
|
||||
struct __wasi_prestat_u_dir_t {
|
||||
size_t pr_name_len;
|
||||
} dir;
|
||||
} u;
|
||||
} __wasi_prestat_t;
|
||||
_Static_assert(offsetof(__wasi_prestat_t, pr_type) == 0, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 4, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 8, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
sizeof(__wasi_prestat_t) == 8, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
sizeof(__wasi_prestat_t) == 16, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
_Alignof(__wasi_prestat_t) == 4, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
_Alignof(__wasi_prestat_t) == 8, "non-wasi data layout");
|
||||
|
||||
typedef struct __wasi_fdstat_t {
|
||||
__wasi_filetype_t fs_filetype;
|
||||
__wasi_fdflags_t fs_flags;
|
||||
__wasi_rights_t fs_rights_base;
|
||||
__wasi_rights_t fs_rights_inheriting;
|
||||
} __wasi_fdstat_t;
|
||||
_Static_assert(
|
||||
offsetof(__wasi_fdstat_t, fs_filetype) == 0, "non-wasi data layout");
|
||||
_Static_assert(offsetof(__wasi_fdstat_t, fs_flags) == 2, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16,
|
||||
"non-wasi data layout");
|
||||
_Static_assert(sizeof(__wasi_fdstat_t) == 24, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(__wasi_fdstat_t) == 8, "non-wasi data layout");
|
||||
|
||||
typedef struct __wasi_filestat_t {
|
||||
__wasi_device_t st_dev;
|
||||
__wasi_inode_t st_ino;
|
||||
__wasi_filetype_t st_filetype;
|
||||
__wasi_linkcount_t st_nlink;
|
||||
__wasi_filesize_t st_size;
|
||||
__wasi_timestamp_t st_atim;
|
||||
__wasi_timestamp_t st_mtim;
|
||||
__wasi_timestamp_t st_ctim;
|
||||
} __wasi_filestat_t;
|
||||
_Static_assert(offsetof(__wasi_filestat_t, st_dev) == 0, "non-wasi data layout");
|
||||
_Static_assert(offsetof(__wasi_filestat_t, st_ino) == 8, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_filestat_t, st_filetype) == 16, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_filestat_t, st_nlink) == 20, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_filestat_t, st_size) == 24, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_filestat_t, st_atim) == 32, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_filestat_t, st_mtim) == 40, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_filestat_t, st_ctim) == 48, "non-wasi data layout");
|
||||
_Static_assert(sizeof(__wasi_filestat_t) == 56, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(__wasi_filestat_t) == 8, "non-wasi data layout");
|
||||
|
||||
typedef struct __wasi_ciovec_t {
|
||||
const void *buf;
|
||||
size_t buf_len;
|
||||
} __wasi_ciovec_t;
|
||||
_Static_assert(offsetof(__wasi_ciovec_t, buf) == 0, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
offsetof(__wasi_ciovec_t, buf_len) == 4, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
offsetof(__wasi_ciovec_t, buf_len) == 8, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
sizeof(__wasi_ciovec_t) == 8, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
sizeof(__wasi_ciovec_t) == 16, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
_Alignof(__wasi_ciovec_t) == 4, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
_Alignof(__wasi_ciovec_t) == 8, "non-wasi data layout");
|
||||
|
||||
typedef struct __wasi_iovec_t {
|
||||
void *buf;
|
||||
size_t buf_len;
|
||||
} __wasi_iovec_t;
|
||||
_Static_assert(offsetof(__wasi_iovec_t, buf) == 0, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
offsetof(__wasi_iovec_t, buf_len) == 4, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
offsetof(__wasi_iovec_t, buf_len) == 8, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
sizeof(__wasi_iovec_t) == 8, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
sizeof(__wasi_iovec_t) == 16, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 4 ||
|
||||
_Alignof(__wasi_iovec_t) == 4, "non-wasi data layout");
|
||||
_Static_assert(sizeof(void *) != 8 ||
|
||||
_Alignof(__wasi_iovec_t) == 8, "non-wasi data layout");
|
||||
|
||||
typedef struct __wasi_subscription_t {
|
||||
__wasi_userdata_t userdata;
|
||||
__wasi_eventtype_t type;
|
||||
union __wasi_subscription_u {
|
||||
struct __wasi_subscription_u_clock_t {
|
||||
__wasi_userdata_t identifier;
|
||||
__wasi_clockid_t clock_id;
|
||||
__wasi_timestamp_t timeout;
|
||||
__wasi_timestamp_t precision;
|
||||
__wasi_subclockflags_t flags;
|
||||
} clock;
|
||||
struct __wasi_subscription_u_fd_readwrite_t {
|
||||
__wasi_fd_t fd;
|
||||
} fd_readwrite;
|
||||
} u;
|
||||
} __wasi_subscription_t;
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, userdata) == 0, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, type) == 8, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, u.clock.identifier) == 16,
|
||||
"non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, u.clock.clock_id) == 24,
|
||||
"non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, u.clock.timeout) == 32, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, u.clock.precision) == 40,
|
||||
"non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, u.clock.flags) == 48, "non-wasi data layout");
|
||||
_Static_assert(
|
||||
offsetof(__wasi_subscription_t, u.fd_readwrite.fd) == 16,
|
||||
"non-wasi data layout");
|
||||
_Static_assert(sizeof(__wasi_subscription_t) == 56, "non-wasi data layout");
|
||||
_Static_assert(_Alignof(__wasi_subscription_t) == 8, "non-wasi data layout");
|
||||
|
||||
#if defined(WASMTIME_SSP_WASI_API)
|
||||
#define WASMTIME_SSP_SYSCALL_NAME(name) \
|
||||
asm("__wasi_" #name)
|
||||
#else
|
||||
#define WASMTIME_SSP_SYSCALL_NAME(name)
|
||||
#endif
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_args_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct argv_environ_values *arg_environ,
|
||||
#endif
|
||||
char **argv,
|
||||
char *argv_buf
|
||||
) WASMTIME_SSP_SYSCALL_NAME(args_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_args_sizes_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct argv_environ_values *arg_environ,
|
||||
#endif
|
||||
size_t *argc,
|
||||
size_t *argv_buf_size
|
||||
) WASMTIME_SSP_SYSCALL_NAME(args_sizes_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_clock_res_get(
|
||||
__wasi_clockid_t clock_id,
|
||||
__wasi_timestamp_t *resolution
|
||||
) WASMTIME_SSP_SYSCALL_NAME(clock_res_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_clock_time_get(
|
||||
__wasi_clockid_t clock_id,
|
||||
__wasi_timestamp_t precision,
|
||||
__wasi_timestamp_t *time
|
||||
) WASMTIME_SSP_SYSCALL_NAME(clock_time_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_environ_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct argv_environ_values *arg_environ,
|
||||
#endif
|
||||
char **environ,
|
||||
char *environ_buf
|
||||
) WASMTIME_SSP_SYSCALL_NAME(environ_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_environ_sizes_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct argv_environ_values *arg_environ,
|
||||
#endif
|
||||
size_t *environ_count,
|
||||
size_t *environ_buf_size
|
||||
) WASMTIME_SSP_SYSCALL_NAME(environ_sizes_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_prestat_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_prestats *prestats,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_prestat_t *buf
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_prestat_dir_name(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_prestats *prestats,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
char *path,
|
||||
size_t path_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_dir_name) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_close(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
struct fd_prestats *prestats,
|
||||
#endif
|
||||
__wasi_fd_t fd
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_close) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_datasync(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_datasync) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_pread(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const __wasi_iovec_t *iovs,
|
||||
size_t iovs_len,
|
||||
__wasi_filesize_t offset,
|
||||
size_t *nread
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_pread) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_pwrite(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const __wasi_ciovec_t *iovs,
|
||||
size_t iovs_len,
|
||||
__wasi_filesize_t offset,
|
||||
size_t *nwritten
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_pwrite) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_read(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const __wasi_iovec_t *iovs,
|
||||
size_t iovs_len,
|
||||
size_t *nread
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_read) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_renumber(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t from,
|
||||
__wasi_fd_t to
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_renumber) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_seek(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_filedelta_t offset,
|
||||
__wasi_whence_t whence,
|
||||
__wasi_filesize_t *newoffset
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_seek) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_tell(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_filesize_t *newoffset
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_tell) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_fdstat_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_fdstat_t *buf
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_fdstat_set_flags(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_fdflags_t flags
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_flags) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_fdstat_set_rights(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_rights_t fs_rights_base,
|
||||
__wasi_rights_t fs_rights_inheriting
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_rights) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_sync(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_sync) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_write(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const __wasi_ciovec_t *iovs,
|
||||
size_t iovs_len,
|
||||
size_t *nwritten
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_write) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_advise(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_filesize_t offset,
|
||||
__wasi_filesize_t len,
|
||||
__wasi_advice_t advice
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_advise) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_allocate(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_filesize_t offset,
|
||||
__wasi_filesize_t len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_allocate) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_create_directory(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const char *path,
|
||||
size_t path_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_create_directory) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_link(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t old_fd,
|
||||
__wasi_lookupflags_t old_flags,
|
||||
const char *old_path,
|
||||
size_t old_path_len,
|
||||
__wasi_fd_t new_fd,
|
||||
const char *new_path,
|
||||
size_t new_path_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_link) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_open(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t dirfd,
|
||||
__wasi_lookupflags_t dirflags,
|
||||
const char *path,
|
||||
size_t path_len,
|
||||
__wasi_oflags_t oflags,
|
||||
__wasi_rights_t fs_rights_base,
|
||||
__wasi_rights_t fs_rights_inheriting,
|
||||
__wasi_fdflags_t fs_flags,
|
||||
__wasi_fd_t *fd
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_open) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_readdir(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
void *buf,
|
||||
size_t buf_len,
|
||||
__wasi_dircookie_t cookie,
|
||||
size_t *bufused
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_readdir) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_readlink(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const char *path,
|
||||
size_t path_len,
|
||||
char *buf,
|
||||
size_t buf_len,
|
||||
size_t *bufused
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_readlink) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_rename(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t old_fd,
|
||||
const char *old_path,
|
||||
size_t old_path_len,
|
||||
__wasi_fd_t new_fd,
|
||||
const char *new_path,
|
||||
size_t new_path_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_rename) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_filestat_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_filestat_t *buf
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_filestat_set_times(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_timestamp_t st_atim,
|
||||
__wasi_timestamp_t st_mtim,
|
||||
__wasi_fstflags_t fstflags
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_times) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_fd_filestat_set_size(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_filesize_t st_size
|
||||
) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_size) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_filestat_get(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_lookupflags_t flags,
|
||||
const char *path,
|
||||
size_t path_len,
|
||||
__wasi_filestat_t *buf
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_filestat_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_filestat_set_times(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
__wasi_lookupflags_t flags,
|
||||
const char *path,
|
||||
size_t path_len,
|
||||
__wasi_timestamp_t st_atim,
|
||||
__wasi_timestamp_t st_mtim,
|
||||
__wasi_fstflags_t fstflags
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_filestat_set_times) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_symlink(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
const char *old_path,
|
||||
size_t old_path_len,
|
||||
__wasi_fd_t fd,
|
||||
const char *new_path,
|
||||
size_t new_path_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_symlink) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_unlink_file(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const char *path,
|
||||
size_t path_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_unlink_file) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_path_remove_directory(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd,
|
||||
const char *path,
|
||||
size_t path_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(path_remove_directory) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_poll_oneoff(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
const __wasi_subscription_t *in,
|
||||
__wasi_event_t *out,
|
||||
size_t nsubscriptions,
|
||||
size_t *nevents
|
||||
) WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) __attribute__((__warn_unused_result__));
|
||||
|
||||
_Noreturn void wasmtime_ssp_proc_exit(
|
||||
__wasi_exitcode_t rval
|
||||
) WASMTIME_SSP_SYSCALL_NAME(proc_exit);
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_proc_raise(
|
||||
__wasi_signal_t sig
|
||||
) WASMTIME_SSP_SYSCALL_NAME(proc_raise) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_random_get(
|
||||
void *buf,
|
||||
size_t buf_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(random_get) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_recv(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
const __wasi_iovec_t *ri_data,
|
||||
size_t ri_data_len,
|
||||
__wasi_riflags_t ri_flags,
|
||||
size_t *ro_datalen,
|
||||
__wasi_roflags_t *ro_flags
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_send(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
const __wasi_ciovec_t *si_data,
|
||||
size_t si_data_len,
|
||||
__wasi_siflags_t si_flags,
|
||||
size_t *so_datalen
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_shutdown(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
__wasi_sdflags_t how
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sched_yield(void)
|
||||
WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef WASMTIME_SSP_SYSCALL_NAME
|
||||
|
||||
#endif
|
||||
24
wasmtime-wasi/sandboxed-system-primitives/src/LICENSE
Normal file
24
wasmtime-wasi/sandboxed-system-primitives/src/LICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
All code is distributed under the following license:
|
||||
|
||||
Copyright (c) 2015 Nuxi, https://nuxi.nl/
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
14
wasmtime-wasi/sandboxed-system-primitives/src/README.md
Normal file
14
wasmtime-wasi/sandboxed-system-primitives/src/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
This directory consists of selected files copied from the [libemulator]
|
||||
directory in the [cloudabi-utils] repository, with minor modifications,
|
||||
along with the accompanying LICENSE file from that repository.
|
||||
|
||||
The modifications are marked with `WASMTIME_*` preprocessor macros.
|
||||
|
||||
The files were copied at git revision
|
||||
be1ce21e1dded9c0c0a6ebe144cbea01cf44a874
|
||||
which is dated
|
||||
Sun Jan 13 23:26:03 2019 +0100
|
||||
.
|
||||
|
||||
[libemulator]: https://github.com/NuxiNL/cloudabi-utils/tree/master/src/libemulator
|
||||
[cloudabi-utils]: https://github.com/NuxiNL/cloudabi-utils
|
||||
93
wasmtime-wasi/sandboxed-system-primitives/src/config.h
Normal file
93
wasmtime-wasi/sandboxed-system-primitives/src/config.h
Normal file
@@ -0,0 +1,93 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#define CONFIG_HAS_ARC4RANDOM_BUF 1
|
||||
#else
|
||||
#define CONFIG_HAS_ARC4RANDOM_BUF 0
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#define CONFIG_HAS_GETENTROPY 1
|
||||
#else
|
||||
#define CONFIG_HAS_GETENTROPY 0
|
||||
#endif
|
||||
|
||||
#if defined(__CloudABI__)
|
||||
#define CONFIG_HAS_CAP_ENTER 1
|
||||
#else
|
||||
#define CONFIG_HAS_CAP_ENTER 0
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__EMSCRIPTEN__)
|
||||
#define CONFIG_HAS_CLOCK_NANOSLEEP 1
|
||||
#else
|
||||
#define CONFIG_HAS_CLOCK_NANOSLEEP 0
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||
#define CONFIG_HAS_FDATASYNC 1
|
||||
#else
|
||||
#define CONFIG_HAS_FDATASYNC 0
|
||||
#endif
|
||||
|
||||
#ifndef __CloudABI__
|
||||
#define CONFIG_HAS_ISATTY 1
|
||||
#else
|
||||
#define CONFIG_HAS_ISATTY 0
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#define CONFIG_HAS_POSIX_FALLOCATE 1
|
||||
#else
|
||||
#define CONFIG_HAS_POSIX_FALLOCATE 0
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#define CONFIG_HAS_PREADV 1
|
||||
#else
|
||||
#define CONFIG_HAS_PREADV 0
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__CloudABI__)
|
||||
#define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1
|
||||
#else
|
||||
#define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 0
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1
|
||||
#else
|
||||
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#define CONFIG_HAS_PWRITEV 1
|
||||
#else
|
||||
#define CONFIG_HAS_PWRITEV 0
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define st_atimespec st_atim
|
||||
#define st_mtimespec st_mtim
|
||||
#define st_ctimespec st_ctim
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define CONFIG_TLS_USE_GSBASE 1
|
||||
#else
|
||||
#define CONFIG_TLS_USE_GSBASE 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
215
wasmtime-wasi/sandboxed-system-primitives/src/locking.h
Normal file
215
wasmtime-wasi/sandboxed-system-primitives/src/locking.h
Normal file
@@ -0,0 +1,215 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef LOCKING_H
|
||||
#define LOCKING_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef __has_extension
|
||||
#define __has_extension(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_extension(c_thread_safety_attributes)
|
||||
#define LOCK_ANNOTATE(x) __attribute__((x))
|
||||
#else
|
||||
#define LOCK_ANNOTATE(x)
|
||||
#endif
|
||||
|
||||
// Lock annotation macros.
|
||||
|
||||
#define LOCKABLE LOCK_ANNOTATE(lockable)
|
||||
|
||||
#define LOCKS_EXCLUSIVE(...) LOCK_ANNOTATE(exclusive_lock_function(__VA_ARGS__))
|
||||
#define LOCKS_SHARED(...) LOCK_ANNOTATE(shared_lock_function(__VA_ARGS__))
|
||||
|
||||
#define TRYLOCKS_EXCLUSIVE(...) \
|
||||
LOCK_ANNOTATE(exclusive_trylock_function(__VA_ARGS__))
|
||||
#define TRYLOCKS_SHARED(...) LOCK_ANNOTATE(shared_trylock_function(__VA_ARGS__))
|
||||
|
||||
#define UNLOCKS(...) LOCK_ANNOTATE(unlock_function(__VA_ARGS__))
|
||||
|
||||
#define REQUIRES_EXCLUSIVE(...) \
|
||||
LOCK_ANNOTATE(exclusive_locks_required(__VA_ARGS__))
|
||||
#define REQUIRES_SHARED(...) LOCK_ANNOTATE(shared_locks_required(__VA_ARGS__))
|
||||
#define REQUIRES_UNLOCKED(...) LOCK_ANNOTATE(locks_excluded(__VA_ARGS__))
|
||||
|
||||
#define NO_LOCK_ANALYSIS LOCK_ANNOTATE(no_thread_safety_analysis)
|
||||
|
||||
// Mutex that uses the lock annotations.
|
||||
|
||||
struct LOCKABLE mutex {
|
||||
pthread_mutex_t object;
|
||||
};
|
||||
|
||||
#define MUTEX_INITIALIZER \
|
||||
{ PTHREAD_MUTEX_INITIALIZER }
|
||||
|
||||
static inline void mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock) {
|
||||
pthread_mutex_init(&lock->object, NULL);
|
||||
}
|
||||
|
||||
static inline void mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock) {
|
||||
pthread_mutex_destroy(&lock->object);
|
||||
}
|
||||
|
||||
static inline void mutex_lock(struct mutex *lock)
|
||||
LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
|
||||
pthread_mutex_lock(&lock->object);
|
||||
}
|
||||
|
||||
static inline void mutex_unlock(struct mutex *lock)
|
||||
UNLOCKS(*lock) NO_LOCK_ANALYSIS {
|
||||
pthread_mutex_unlock(&lock->object);
|
||||
}
|
||||
|
||||
// Read-write lock that uses the lock annotations.
|
||||
|
||||
struct LOCKABLE rwlock {
|
||||
pthread_rwlock_t object;
|
||||
};
|
||||
|
||||
static inline void rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) {
|
||||
pthread_rwlock_init(&lock->object, NULL);
|
||||
}
|
||||
|
||||
static inline void rwlock_rdlock(struct rwlock *lock)
|
||||
LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS {
|
||||
pthread_rwlock_rdlock(&lock->object);
|
||||
}
|
||||
|
||||
static inline void rwlock_wrlock(struct rwlock *lock)
|
||||
LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
|
||||
pthread_rwlock_wrlock(&lock->object);
|
||||
}
|
||||
|
||||
static inline void rwlock_unlock(struct rwlock *lock)
|
||||
UNLOCKS(*lock) NO_LOCK_ANALYSIS {
|
||||
pthread_rwlock_unlock(&lock->object);
|
||||
}
|
||||
|
||||
// Condition variable that uses the lock annotations.
|
||||
|
||||
struct LOCKABLE cond {
|
||||
pthread_cond_t object;
|
||||
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \
|
||||
!CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
|
||||
clockid_t clock;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void cond_init_monotonic(struct cond *cond) {
|
||||
#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
|
||||
pthread_condattr_t attr;
|
||||
pthread_condattr_init(&attr);
|
||||
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
pthread_cond_init(&cond->object, &attr);
|
||||
pthread_condattr_destroy(&attr);
|
||||
#else
|
||||
pthread_cond_init(&cond->object, NULL);
|
||||
#endif
|
||||
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \
|
||||
!CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
|
||||
cond->clock = CLOCK_MONOTONIC;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void cond_init_realtime(struct cond *cond) {
|
||||
pthread_cond_init(&cond->object, NULL);
|
||||
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \
|
||||
!CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
|
||||
cond->clock = CLOCK_REALTIME;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void cond_destroy(struct cond *cond) {
|
||||
pthread_cond_destroy(&cond->object);
|
||||
}
|
||||
|
||||
static inline void cond_signal(struct cond *cond) {
|
||||
pthread_cond_signal(&cond->object);
|
||||
}
|
||||
|
||||
static inline bool cond_timedwait(struct cond *cond, struct mutex *lock,
|
||||
uint64_t timeout, bool abstime)
|
||||
REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
|
||||
struct timespec ts = {
|
||||
.tv_sec = (time_t)(timeout / 1000000000),
|
||||
.tv_nsec = (long)(timeout % 1000000000),
|
||||
};
|
||||
|
||||
if (abstime) {
|
||||
#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
|
||||
// No native support for sleeping on monotonic clocks. Convert the
|
||||
// timeout to a relative value and then to an absolute value for the
|
||||
// realtime clock.
|
||||
if (cond->clock != CLOCK_REALTIME) {
|
||||
struct timespec ts_monotonic;
|
||||
clock_gettime(cond->clock, &ts_monotonic);
|
||||
ts.tv_sec -= ts_monotonic.tv_sec;
|
||||
ts.tv_nsec -= ts_monotonic.tv_nsec;
|
||||
if (ts.tv_nsec < 0) {
|
||||
ts.tv_nsec += 1000000000;
|
||||
--ts.tv_sec;
|
||||
}
|
||||
|
||||
struct timespec ts_realtime;
|
||||
clock_gettime(CLOCK_REALTIME, &ts_realtime);
|
||||
ts.tv_sec += ts_realtime.tv_sec;
|
||||
ts.tv_nsec += ts_realtime.tv_nsec;
|
||||
if (ts.tv_nsec >= 1000000000) {
|
||||
ts.tv_nsec -= 1000000000;
|
||||
++ts.tv_sec;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
|
||||
// Implementation supports relative timeouts.
|
||||
int ret =
|
||||
pthread_cond_timedwait_relative_np(&cond->object, &lock->object, &ts);
|
||||
assert((ret == 0 || ret == ETIMEDOUT) &&
|
||||
"pthread_cond_timedwait_relative_np() failed");
|
||||
return ret == ETIMEDOUT;
|
||||
#else
|
||||
// Convert to absolute timeout.
|
||||
struct timespec ts_now;
|
||||
#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK
|
||||
clock_gettime(cond->clock, &ts_now);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ts_now);
|
||||
#endif
|
||||
ts.tv_sec += ts_now.tv_sec;
|
||||
ts.tv_nsec += ts_now.tv_nsec;
|
||||
if (ts.tv_nsec >= 1000000000) {
|
||||
ts.tv_nsec -= 1000000000;
|
||||
++ts.tv_sec;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts);
|
||||
assert((ret == 0 || ret == ETIMEDOUT) && "pthread_cond_timedwait() failed");
|
||||
return ret == ETIMEDOUT;
|
||||
}
|
||||
|
||||
static inline void cond_wait(struct cond *cond, struct mutex *lock)
|
||||
REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS {
|
||||
pthread_cond_wait(&cond->object, &lock->object);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2015 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef COMMON_LIMITS_H
|
||||
#define COMMON_LIMITS_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define NUMERIC_MIN(t) \
|
||||
_Generic((t)0, char \
|
||||
: CHAR_MIN, signed char \
|
||||
: SCHAR_MIN, unsigned char : 0, short \
|
||||
: SHRT_MIN, unsigned short : 0, int \
|
||||
: INT_MIN, unsigned int : 0, long \
|
||||
: LONG_MIN, unsigned long : 0, long long \
|
||||
: LLONG_MIN, unsigned long long : 0, default \
|
||||
: (void)0)
|
||||
|
||||
#define NUMERIC_MAX(t) \
|
||||
_Generic((t)0, char \
|
||||
: CHAR_MAX, signed char \
|
||||
: SCHAR_MAX, unsigned char \
|
||||
: UCHAR_MAX, short \
|
||||
: SHRT_MAX, unsigned short \
|
||||
: USHRT_MAX, int \
|
||||
: INT_MAX, unsigned int \
|
||||
: UINT_MAX, long \
|
||||
: LONG_MAX, unsigned long \
|
||||
: ULONG_MAX, long long \
|
||||
: LLONG_MAX, unsigned long long \
|
||||
: ULLONG_MAX, default \
|
||||
: (void)0)
|
||||
|
||||
#endif
|
||||
2817
wasmtime-wasi/sandboxed-system-primitives/src/posix.c
Normal file
2817
wasmtime-wasi/sandboxed-system-primitives/src/posix.c
Normal file
File diff suppressed because it is too large
Load Diff
59
wasmtime-wasi/sandboxed-system-primitives/src/posix.h
Normal file
59
wasmtime-wasi/sandboxed-system-primitives/src/posix.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016-2018 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef POSIX_H
|
||||
#define POSIX_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "locking.h"
|
||||
|
||||
struct fd_entry;
|
||||
struct fd_prestat;
|
||||
struct syscalls;
|
||||
|
||||
struct fd_table {
|
||||
struct rwlock lock;
|
||||
struct fd_entry *entries;
|
||||
size_t size;
|
||||
size_t used;
|
||||
};
|
||||
|
||||
struct fd_prestats {
|
||||
struct rwlock lock;
|
||||
struct fd_prestat *prestats;
|
||||
size_t size;
|
||||
size_t used;
|
||||
};
|
||||
|
||||
struct argv_environ_values {
|
||||
size_t argc;
|
||||
size_t argv_buf_size;
|
||||
char **argv;
|
||||
char *argv_buf;
|
||||
size_t environ_count;
|
||||
size_t environ_buf_size;
|
||||
char **environ;
|
||||
char *environ_buf;
|
||||
};
|
||||
|
||||
void fd_table_init(struct fd_table *);
|
||||
bool fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int);
|
||||
void fd_prestats_init(struct fd_prestats *);
|
||||
bool fd_prestats_insert(struct fd_prestats *, const char *, __wasi_fd_t);
|
||||
void argv_environ_init(struct argv_environ_values *,
|
||||
const size_t *argv_offsets, size_t argv_offsets_len,
|
||||
const char *argv_buf, size_t argv_buf_len,
|
||||
const size_t *environ_offsets, size_t environ_offsets_len,
|
||||
const char *environ_buf, size_t environ_buf_len);
|
||||
|
||||
#endif
|
||||
92
wasmtime-wasi/sandboxed-system-primitives/src/queue.h
Normal file
92
wasmtime-wasi/sandboxed-system-primitives/src/queue.h
Normal file
@@ -0,0 +1,92 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// LIST: Double-linked list.
|
||||
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *l_first; \
|
||||
}
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *l_next; \
|
||||
struct type **l_prev; \
|
||||
}
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = (head)->l_first; (var) != NULL; (var) = (var)->field.l_next)
|
||||
#define LIST_INIT(head) \
|
||||
do { \
|
||||
(head)->l_first = NULL; \
|
||||
} while (0)
|
||||
#define LIST_INSERT_HEAD(head, element, field) \
|
||||
do { \
|
||||
(element)->field.l_next = (head)->l_first; \
|
||||
if ((head)->l_first != NULL) \
|
||||
(head)->l_first->field.l_prev = &(element)->field.l_next; \
|
||||
(head)->l_first = (element); \
|
||||
(element)->field.l_prev = &(head)->l_first; \
|
||||
} while (0)
|
||||
#define LIST_REMOVE(element, field) \
|
||||
do { \
|
||||
if ((element)->field.l_next != NULL) \
|
||||
(element)->field.l_next->field.l_prev = (element)->field.l_prev; \
|
||||
*(element)->field.l_prev = (element)->field.l_next; \
|
||||
} while (0)
|
||||
|
||||
// TAILQ: Double-linked list with tail pointer.
|
||||
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *t_first; \
|
||||
struct type **t_last; \
|
||||
}
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *t_next; \
|
||||
struct type **t_prev; \
|
||||
}
|
||||
|
||||
#define TAILQ_EMPTY(head) ((head)->t_first == NULL)
|
||||
#define TAILQ_FIRST(head) ((head)->t_first)
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = (head)->t_first; (var) != NULL; (var) = (var)->field.t_next)
|
||||
#define TAILQ_INIT(head) \
|
||||
do { \
|
||||
(head)->t_first = NULL; \
|
||||
(head)->t_last = &(head)->t_first; \
|
||||
} while (0)
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) \
|
||||
do { \
|
||||
(elm)->field.t_next = NULL; \
|
||||
(elm)->field.t_prev = (head)->t_last; \
|
||||
*(head)->t_last = (elm); \
|
||||
(head)->t_last = &(elm)->field.t_next; \
|
||||
} while (0)
|
||||
#define TAILQ_REMOVE(head, element, field) \
|
||||
do { \
|
||||
if ((element)->field.t_next != NULL) \
|
||||
(element)->field.t_next->field.t_prev = (element)->field.t_prev; \
|
||||
else \
|
||||
(head)->t_last = (element)->field.t_prev; \
|
||||
*(element)->field.t_prev = (element)->field.t_next; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
76
wasmtime-wasi/sandboxed-system-primitives/src/random.c
Normal file
76
wasmtime-wasi/sandboxed-system-primitives/src/random.c
Normal file
@@ -0,0 +1,76 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "random.h"
|
||||
|
||||
#if CONFIG_HAS_ARC4RANDOM_BUF
|
||||
|
||||
void random_buf(void *buf, size_t len) {
|
||||
arc4random_buf(buf, len);
|
||||
}
|
||||
|
||||
#elif CONFIG_HAS_GETENTROPY
|
||||
|
||||
void random_buf(void *buf, size_t len) {
|
||||
getentropy(buf, len);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int urandom;
|
||||
|
||||
static void open_urandom(void) {
|
||||
urandom = open("/dev/urandom", O_RDONLY);
|
||||
if (urandom < 0) {
|
||||
fputs("Failed to open /dev/urandom\n", stderr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void random_buf(void *buf, size_t len) {
|
||||
static pthread_once_t open_once = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&open_once, open_urandom);
|
||||
|
||||
if (read(urandom, buf, len) != len) {
|
||||
fputs("Short read on /dev/urandom\n", stderr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Calculates a random number within the range [0, upper - 1] without
|
||||
// any modulo bias.
|
||||
//
|
||||
// The function below repeatedly obtains a random number from
|
||||
// arc4random() until it lies within the range [2^k % upper, 2^k). As
|
||||
// this range has length k * upper, we can safely obtain a number
|
||||
// without any modulo bias.
|
||||
uintmax_t random_uniform(uintmax_t upper) {
|
||||
// Compute 2^k % upper
|
||||
// == (2^k - upper) % upper
|
||||
// == -upper % upper.
|
||||
uintmax_t lower = -upper % upper;
|
||||
for (;;) {
|
||||
uintmax_t value;
|
||||
random_buf(&value, sizeof(value));
|
||||
if (value >= lower)
|
||||
return value % upper;
|
||||
}
|
||||
}
|
||||
20
wasmtime-wasi/sandboxed-system-primitives/src/random.h
Normal file
20
wasmtime-wasi/sandboxed-system-primitives/src/random.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef RANDOM_H
|
||||
#define RANDOM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void random_buf(void *, size_t);
|
||||
uintmax_t random_uniform(uintmax_t);
|
||||
|
||||
#endif
|
||||
47
wasmtime-wasi/sandboxed-system-primitives/src/refcount.h
Normal file
47
wasmtime-wasi/sandboxed-system-primitives/src/refcount.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef REFCOUNT_H
|
||||
#define REFCOUNT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "locking.h"
|
||||
|
||||
// Simple reference counter.
|
||||
struct LOCKABLE refcount {
|
||||
atomic_uint count;
|
||||
};
|
||||
|
||||
#define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS
|
||||
#define CONSUMES(...) UNLOCKS(__VA_ARGS__) NO_LOCK_ANALYSIS
|
||||
|
||||
// Initialize the reference counter.
|
||||
static void refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) {
|
||||
atomic_init(&r->count, count);
|
||||
}
|
||||
|
||||
// Increment the reference counter.
|
||||
static inline void refcount_acquire(struct refcount *r) PRODUCES(*r) {
|
||||
atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire);
|
||||
}
|
||||
|
||||
// Decrement the reference counter, returning whether the reference
|
||||
// dropped to zero.
|
||||
static inline bool refcount_release(struct refcount *r) CONSUMES(*r) {
|
||||
int old = atomic_fetch_sub_explicit(&r->count, 1, memory_order_release);
|
||||
assert(old != 0 && "Reference count becoming negative");
|
||||
return old == 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
82
wasmtime-wasi/sandboxed-system-primitives/src/rights.h
Normal file
82
wasmtime-wasi/sandboxed-system-primitives/src/rights.h
Normal file
@@ -0,0 +1,82 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef RIGHTS_H
|
||||
#define RIGHTS_H
|
||||
|
||||
#define RIGHTS_ALL \
|
||||
(__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_READ | \
|
||||
__WASI_RIGHT_FD_SEEK | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
|
||||
__WASI_RIGHT_FD_SYNC | __WASI_RIGHT_FD_TELL | __WASI_RIGHT_FD_WRITE | \
|
||||
__WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_FD_ALLOCATE | \
|
||||
__WASI_RIGHT_PATH_CREATE_DIRECTORY | __WASI_RIGHT_PATH_CREATE_FILE | \
|
||||
__WASI_RIGHT_PATH_LINK_SOURCE | __WASI_RIGHT_PATH_LINK_TARGET | \
|
||||
__WASI_RIGHT_PATH_OPEN | __WASI_RIGHT_FD_READDIR | \
|
||||
__WASI_RIGHT_PATH_READLINK | __WASI_RIGHT_PATH_RENAME_SOURCE | \
|
||||
__WASI_RIGHT_PATH_RENAME_TARGET | __WASI_RIGHT_PATH_FILESTAT_GET | \
|
||||
__WASI_RIGHT_PATH_FILESTAT_SET_SIZE | \
|
||||
__WASI_RIGHT_PATH_FILESTAT_SET_TIMES | \
|
||||
__WASI_RIGHT_FD_FILESTAT_GET | __WASI_RIGHT_FD_FILESTAT_SET_TIMES | \
|
||||
__WASI_RIGHT_FD_FILESTAT_SET_SIZE | \
|
||||
__WASI_RIGHT_PATH_SYMLINK | __WASI_RIGHT_PATH_UNLINK_FILE | \
|
||||
__WASI_RIGHT_PATH_REMOVE_DIRECTORY | \
|
||||
__WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_SHUTDOWN)
|
||||
|
||||
// Block and character device interaction is outside the scope of
|
||||
// CloudABI. Simply allow everything.
|
||||
#define RIGHTS_BLOCK_DEVICE_BASE RIGHTS_ALL
|
||||
#define RIGHTS_BLOCK_DEVICE_INHERITING RIGHTS_ALL
|
||||
#define RIGHTS_CHARACTER_DEVICE_BASE RIGHTS_ALL
|
||||
#define RIGHTS_CHARACTER_DEVICE_INHERITING RIGHTS_ALL
|
||||
|
||||
// Only allow directory operations on directories. Directories can only
|
||||
// yield file descriptors to other directories and files.
|
||||
#define RIGHTS_DIRECTORY_BASE \
|
||||
(__WASI_RIGHT_FD_FDSTAT_SET_FLAGS | __WASI_RIGHT_FD_SYNC | \
|
||||
__WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_PATH_CREATE_DIRECTORY | \
|
||||
__WASI_RIGHT_PATH_CREATE_FILE | __WASI_RIGHT_PATH_LINK_SOURCE | \
|
||||
__WASI_RIGHT_PATH_LINK_TARGET | __WASI_RIGHT_PATH_OPEN | \
|
||||
__WASI_RIGHT_FD_READDIR | __WASI_RIGHT_PATH_READLINK | \
|
||||
__WASI_RIGHT_PATH_RENAME_SOURCE | __WASI_RIGHT_PATH_RENAME_TARGET | \
|
||||
__WASI_RIGHT_PATH_FILESTAT_GET | \
|
||||
__WASI_RIGHT_PATH_FILESTAT_SET_TIMES | \
|
||||
__WASI_RIGHT_FD_FILESTAT_GET | __WASI_RIGHT_FD_FILESTAT_SET_TIMES | \
|
||||
__WASI_RIGHT_PATH_SYMLINK | __WASI_RIGHT_PATH_UNLINK_FILE | \
|
||||
__WASI_RIGHT_PATH_REMOVE_DIRECTORY | \
|
||||
__WASI_RIGHT_POLL_FD_READWRITE)
|
||||
#define RIGHTS_DIRECTORY_INHERITING \
|
||||
(RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE)
|
||||
|
||||
// Operations that apply to regular files.
|
||||
#define RIGHTS_REGULAR_FILE_BASE \
|
||||
(__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_READ | \
|
||||
__WASI_RIGHT_FD_SEEK | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
|
||||
__WASI_RIGHT_FD_SYNC | __WASI_RIGHT_FD_TELL | __WASI_RIGHT_FD_WRITE | \
|
||||
__WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_FD_ALLOCATE | \
|
||||
__WASI_RIGHT_FD_FILESTAT_GET | __WASI_RIGHT_FD_FILESTAT_SET_SIZE | \
|
||||
__WASI_RIGHT_FD_FILESTAT_SET_TIMES | __WASI_RIGHT_POLL_FD_READWRITE)
|
||||
#define RIGHTS_REGULAR_FILE_INHERITING 0
|
||||
|
||||
// Operations that apply to sockets and socket pairs.
|
||||
#define RIGHTS_SOCKET_BASE \
|
||||
(__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
|
||||
__WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET | \
|
||||
__WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_SHUTDOWN)
|
||||
#define RIGHTS_SOCKET_INHERITING RIGHTS_ALL
|
||||
|
||||
// Operations that apply to TTYs.
|
||||
#define RIGHTS_TTY_BASE \
|
||||
(__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
|
||||
__WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET | \
|
||||
__WASI_RIGHT_POLL_FD_READWRITE)
|
||||
#define RIGHTS_TTY_INHERITING 0
|
||||
|
||||
#endif
|
||||
17
wasmtime-wasi/sandboxed-system-primitives/src/signals.h
Normal file
17
wasmtime-wasi/sandboxed-system-primitives/src/signals.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef SIGNALS_H
|
||||
#define SIGNALS_H
|
||||
|
||||
void signals_init(void);
|
||||
|
||||
#endif
|
||||
33
wasmtime-wasi/sandboxed-system-primitives/src/str.c
Normal file
33
wasmtime-wasi/sandboxed-system-primitives/src/str.c
Normal file
@@ -0,0 +1,33 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "str.h"
|
||||
|
||||
char *str_nullterminate(const char *s, size_t len) {
|
||||
// Copy string.
|
||||
char *ret = strndup(s, len);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
// Ensure that it contains no null bytes within.
|
||||
if (strlen(ret) != len) {
|
||||
free(ret);
|
||||
errno = EILSEQ;
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
19
wasmtime-wasi/sandboxed-system-primitives/src/str.h
Normal file
19
wasmtime-wasi/sandboxed-system-primitives/src/str.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information.
|
||||
//
|
||||
// Significant parts of this file are derived from cloudabi-utils. See
|
||||
// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
|
||||
// for license information.
|
||||
//
|
||||
// The upstream file contains the following copyright notice:
|
||||
//
|
||||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
||||
|
||||
#ifndef STR_H
|
||||
#define STR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
char *str_nullterminate(const char *, size_t);
|
||||
|
||||
#endif
|
||||
6
wasmtime-wasi/src/host.rs
Normal file
6
wasmtime-wasi/src/host.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
#![allow(non_camel_case_types, dead_code)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/wasmtime_ssp.rs"));
|
||||
|
||||
pub type char = ::std::os::raw::c_char;
|
||||
pub type void = ::std::os::raw::c_void;
|
||||
203
wasmtime-wasi/src/instantiate.rs
Normal file
203
wasmtime-wasi/src/instantiate.rs
Normal file
@@ -0,0 +1,203 @@
|
||||
use crate::host::{
|
||||
argv_environ_init, argv_environ_values, fd_prestats, fd_prestats_init, fd_prestats_insert,
|
||||
fd_table, fd_table_init, fd_table_insert_existing,
|
||||
};
|
||||
use cranelift_codegen::ir::types;
|
||||
use cranelift_codegen::{ir, isa};
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::DefinedFuncIndex;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use syscalls;
|
||||
use target_lexicon::HOST;
|
||||
use wasmtime_environ::{translate_signature, Export, Module};
|
||||
use wasmtime_runtime::{Imports, InstanceHandle, InstantiationError, VMFunctionBody};
|
||||
|
||||
pub(crate) struct WASIState {
|
||||
pub curfds: Box<fd_table>,
|
||||
pub prestats: Box<fd_prestats>,
|
||||
pub argv_environ: Box<argv_environ_values>,
|
||||
}
|
||||
|
||||
/// Return an instance implementing the "wasi" interface.
|
||||
pub fn instantiate_wasi(
|
||||
prefix: &str,
|
||||
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||
preopened_dirs: &[(String, libc::c_int)],
|
||||
argv: &[String],
|
||||
environ: &[(String, String)],
|
||||
) -> Result<InstanceHandle, InstantiationError> {
|
||||
let pointer_type = types::Type::triple_pointer_type(&HOST);
|
||||
let mut module = Module::new();
|
||||
let mut finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody> =
|
||||
PrimaryMap::new();
|
||||
let call_conv = isa::CallConv::triple_default(&HOST);
|
||||
|
||||
macro_rules! signature {
|
||||
($name:ident) => {{
|
||||
let sig = module.signatures.push(translate_signature(
|
||||
ir::Signature {
|
||||
params: syscalls::$name::params()
|
||||
.into_iter()
|
||||
.map(ir::AbiParam::new)
|
||||
.collect(),
|
||||
returns: syscalls::$name::results()
|
||||
.into_iter()
|
||||
.map(ir::AbiParam::new)
|
||||
.collect(),
|
||||
call_conv,
|
||||
},
|
||||
pointer_type,
|
||||
));
|
||||
let func = module.functions.push(sig);
|
||||
module.exports.insert(
|
||||
prefix.to_owned() + stringify!($name),
|
||||
Export::Function(func),
|
||||
);
|
||||
finished_functions.push(syscalls::$name::SHIM as *const VMFunctionBody);
|
||||
}};
|
||||
}
|
||||
|
||||
signature!(args_get);
|
||||
signature!(args_sizes_get);
|
||||
signature!(clock_res_get);
|
||||
signature!(clock_time_get);
|
||||
signature!(environ_get);
|
||||
signature!(environ_sizes_get);
|
||||
signature!(fd_prestat_get);
|
||||
signature!(fd_prestat_dir_name);
|
||||
signature!(fd_close);
|
||||
signature!(fd_datasync);
|
||||
signature!(fd_pread);
|
||||
signature!(fd_pwrite);
|
||||
signature!(fd_read);
|
||||
signature!(fd_renumber);
|
||||
signature!(fd_seek);
|
||||
signature!(fd_tell);
|
||||
signature!(fd_fdstat_get);
|
||||
signature!(fd_fdstat_set_flags);
|
||||
signature!(fd_fdstat_set_rights);
|
||||
signature!(fd_sync);
|
||||
signature!(fd_write);
|
||||
signature!(fd_advise);
|
||||
signature!(fd_allocate);
|
||||
signature!(path_create_directory);
|
||||
signature!(path_link);
|
||||
signature!(path_open);
|
||||
signature!(fd_readdir);
|
||||
signature!(path_readlink);
|
||||
signature!(path_rename);
|
||||
signature!(fd_filestat_get);
|
||||
signature!(fd_filestat_set_times);
|
||||
signature!(fd_filestat_set_size);
|
||||
signature!(path_filestat_get);
|
||||
signature!(path_filestat_set_times);
|
||||
signature!(path_symlink);
|
||||
signature!(path_unlink_file);
|
||||
signature!(path_remove_directory);
|
||||
signature!(poll_oneoff);
|
||||
signature!(proc_exit);
|
||||
signature!(proc_raise);
|
||||
signature!(random_get);
|
||||
signature!(sched_yield);
|
||||
signature!(sock_recv);
|
||||
signature!(sock_send);
|
||||
signature!(sock_shutdown);
|
||||
|
||||
let imports = Imports::none();
|
||||
let data_initializers = Vec::new();
|
||||
let signatures = PrimaryMap::new();
|
||||
let mut curfds = Box::new(unsafe { mem::zeroed::<fd_table>() });
|
||||
let mut prestats = Box::new(unsafe { mem::zeroed::<fd_prestats>() });
|
||||
let mut argv_environ = Box::new(unsafe { mem::zeroed::<argv_environ_values>() });
|
||||
|
||||
unsafe {
|
||||
let argv_environ: &mut argv_environ_values = &mut *argv_environ;
|
||||
let (argv_offsets, argv_buf, environ_offsets, environ_buf) =
|
||||
allocate_argv_environ(argv, environ);
|
||||
argv_environ_init(
|
||||
argv_environ,
|
||||
argv_offsets.as_ptr(),
|
||||
argv_offsets.len(),
|
||||
argv_buf.as_ptr(),
|
||||
argv_buf.len(),
|
||||
environ_offsets.as_ptr(),
|
||||
environ_offsets.len(),
|
||||
environ_buf.as_ptr(),
|
||||
environ_buf.len(),
|
||||
);
|
||||
|
||||
let curfds: *mut fd_table = &mut *curfds;
|
||||
fd_table_init(curfds);
|
||||
|
||||
let prestats: *mut fd_prestats = &mut *prestats;
|
||||
fd_prestats_init(prestats);
|
||||
|
||||
// Prepopulate curfds with stdin, stdout, and stderr file descriptors.
|
||||
assert!(fd_table_insert_existing(curfds, 0, 0));
|
||||
assert!(fd_table_insert_existing(curfds, 1, 1));
|
||||
assert!(fd_table_insert_existing(curfds, 2, 2));
|
||||
|
||||
let mut wasm_fd = 3;
|
||||
for (dir, fd) in preopened_dirs {
|
||||
assert!(fd_table_insert_existing(curfds, wasm_fd, *fd));
|
||||
assert!(fd_prestats_insert(
|
||||
prestats,
|
||||
CString::new(dir.as_str()).unwrap().as_ptr(),
|
||||
wasm_fd,
|
||||
));
|
||||
wasm_fd += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let host_state = WASIState {
|
||||
curfds,
|
||||
prestats,
|
||||
argv_environ,
|
||||
};
|
||||
|
||||
InstanceHandle::new(
|
||||
Rc::new(module),
|
||||
global_exports,
|
||||
finished_functions.into_boxed_slice(),
|
||||
imports,
|
||||
&data_initializers,
|
||||
signatures.into_boxed_slice(),
|
||||
None,
|
||||
Box::new(host_state),
|
||||
)
|
||||
}
|
||||
|
||||
fn allocate_argv_environ(
|
||||
argv: &[String],
|
||||
environ: &[(String, String)],
|
||||
) -> (Vec<usize>, Vec<libc::c_char>, Vec<usize>, Vec<libc::c_char>) {
|
||||
let mut argv_offsets = Vec::new();
|
||||
let mut argv_buf = Vec::new();
|
||||
let mut environ_offsets = Vec::new();
|
||||
let mut environ_buf = Vec::new();
|
||||
|
||||
for arg in argv {
|
||||
argv_offsets.push(argv_buf.len());
|
||||
for c in arg.bytes() {
|
||||
argv_buf.push(c as libc::c_char);
|
||||
}
|
||||
argv_buf.push('\0' as libc::c_char);
|
||||
}
|
||||
for (key, value) in environ {
|
||||
environ_offsets.push(environ_buf.len());
|
||||
for c in key.bytes() {
|
||||
environ_buf.push(c as libc::c_char);
|
||||
}
|
||||
environ_buf.push('=' as libc::c_char);
|
||||
for c in value.bytes() {
|
||||
environ_buf.push(c as libc::c_char);
|
||||
}
|
||||
environ_buf.push('\0' as libc::c_char);
|
||||
}
|
||||
|
||||
(argv_offsets, argv_buf, environ_offsets, environ_buf)
|
||||
}
|
||||
18
wasmtime-wasi/src/lib.rs
Normal file
18
wasmtime-wasi/src/lib.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
extern crate cast;
|
||||
extern crate cranelift_codegen;
|
||||
extern crate cranelift_entity;
|
||||
extern crate cranelift_wasm;
|
||||
extern crate target_lexicon;
|
||||
extern crate wasmtime_environ;
|
||||
extern crate wasmtime_jit;
|
||||
extern crate wasmtime_runtime;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod host;
|
||||
mod instantiate;
|
||||
mod syscalls;
|
||||
mod translate;
|
||||
mod wasm32;
|
||||
|
||||
pub use instantiate::instantiate_wasi;
|
||||
1521
wasmtime-wasi/src/syscalls.rs
Normal file
1521
wasmtime-wasi/src/syscalls.rs
Normal file
File diff suppressed because it is too large
Load Diff
508
wasmtime-wasi/src/translate.rs
Normal file
508
wasmtime-wasi/src/translate.rs
Normal file
@@ -0,0 +1,508 @@
|
||||
use cast;
|
||||
use cast::From as _0;
|
||||
use host;
|
||||
use std::mem::{align_of, size_of};
|
||||
use std::slice;
|
||||
use wasm32;
|
||||
use wasmtime_runtime::{Export, VMContext};
|
||||
|
||||
/// Translate a wasm pointer into a native pointer.
|
||||
///
|
||||
/// This is unsafe due to trusting the contents of vmctx. The pointer result
|
||||
/// is bounds and alignment checked.
|
||||
unsafe fn decode_ptr(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: usize,
|
||||
align: usize,
|
||||
) -> Result<*mut u8, host::__wasi_errno_t> {
|
||||
match vmctx.lookup_global_export("memory") {
|
||||
Some(Export::Memory {
|
||||
definition,
|
||||
vmctx: _,
|
||||
memory: _,
|
||||
}) => {
|
||||
if len > 0 {
|
||||
// Check for overflow within the access.
|
||||
let last = match (ptr as usize).checked_add(len - 1) {
|
||||
Some(sum) => sum,
|
||||
None => {
|
||||
println!("!!! overflow");
|
||||
return Err(host::__WASI_EFAULT as host::__wasi_errno_t);
|
||||
}
|
||||
};
|
||||
// Check for out of bounds.
|
||||
if last >= (*definition).current_length {
|
||||
println!("!!! out of bounds");
|
||||
return Err(host::__WASI_EFAULT as host::__wasi_errno_t);
|
||||
}
|
||||
}
|
||||
// Check alignment.
|
||||
if (ptr as usize) % align != 0 {
|
||||
println!("!!! bad alignment: {} % {}", ptr, align);
|
||||
return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
|
||||
}
|
||||
// Ok, translate the address.
|
||||
Ok((((*definition).base as usize) + (ptr as usize)) as *mut u8)
|
||||
}
|
||||
// No export named "__wasi_memory", or the export isn't a memory.
|
||||
// FIXME: Is EINVAL the best code here?
|
||||
x => {
|
||||
println!(
|
||||
"!!! no export named __wasi_memory, or the export isn't a mem: {:?}",
|
||||
x
|
||||
);
|
||||
Err(host::__WASI_EINVAL as host::__wasi_errno_t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn decode_ptr_to<T>(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
) -> Result<*mut T, host::__wasi_errno_t> {
|
||||
decode_ptr(vmctx, ptr, size_of::<T>(), align_of::<T>()).map(|ptr| ptr as *mut T)
|
||||
}
|
||||
|
||||
unsafe fn decode_pointee<T>(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
) -> Result<T, host::__wasi_errno_t> {
|
||||
let ptr = decode_ptr_to::<T>(vmctx, ptr)?;
|
||||
|
||||
// Size and alignment are checked by `decode_ptr_to`.
|
||||
Ok(ptr.read())
|
||||
}
|
||||
|
||||
pub unsafe fn encode_pointee<T>(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
t: T,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
let ptr = decode_ptr_to::<T>(vmctx, ptr)?;
|
||||
|
||||
// Size and alignment are checked by `decode_ptr_to`.
|
||||
Ok(ptr.write(t))
|
||||
}
|
||||
|
||||
pub unsafe fn decode_slice_of<T>(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: wasm32::size_t,
|
||||
) -> Result<(*mut T, usize), host::__wasi_errno_t> {
|
||||
let len = cast::usize(len);
|
||||
|
||||
let ptr = decode_ptr(
|
||||
vmctx,
|
||||
ptr,
|
||||
size_of::<T>().checked_mul(len).unwrap(),
|
||||
align_of::<T>(),
|
||||
)? as *mut T;
|
||||
|
||||
Ok((ptr, len))
|
||||
}
|
||||
|
||||
pub fn decode_usize(len: wasm32::size_t) -> usize {
|
||||
cast::usize(len)
|
||||
}
|
||||
|
||||
pub fn encode_usize(len: usize) -> wasm32::size_t {
|
||||
cast::u32(len).unwrap()
|
||||
}
|
||||
|
||||
pub unsafe fn decode_filesize(filesize: wasm32::__wasi_filesize_t) -> host::__wasi_filesize_t {
|
||||
filesize
|
||||
}
|
||||
|
||||
pub fn decode_fd(fd: wasm32::__wasi_fd_t) -> host::__wasi_fd_t {
|
||||
fd
|
||||
}
|
||||
|
||||
pub fn decode_filedelta(filedelta: wasm32::__wasi_filedelta_t) -> host::__wasi_filedelta_t {
|
||||
filedelta
|
||||
}
|
||||
|
||||
pub fn decode_whence(whence: wasm32::__wasi_whence_t) -> host::__wasi_whence_t {
|
||||
whence
|
||||
}
|
||||
|
||||
pub fn decode_clockid(clockid: wasm32::__wasi_clockid_t) -> host::__wasi_clockid_t {
|
||||
clockid
|
||||
}
|
||||
|
||||
pub fn decode_timestamp(timestamp: wasm32::__wasi_timestamp_t) -> host::__wasi_timestamp_t {
|
||||
timestamp
|
||||
}
|
||||
|
||||
pub fn decode_exitcode(exitcode: wasm32::__wasi_exitcode_t) -> host::__wasi_exitcode_t {
|
||||
exitcode
|
||||
}
|
||||
|
||||
pub fn decode_lookupflags(lookupflags: wasm32::__wasi_lookupflags_t) -> host::__wasi_lookupflags_t {
|
||||
lookupflags
|
||||
}
|
||||
|
||||
pub fn decode_roflags(roflags: wasm32::__wasi_roflags_t) -> host::__wasi_roflags_t {
|
||||
roflags
|
||||
}
|
||||
|
||||
pub fn decode_oflags(oflags: wasm32::__wasi_oflags_t) -> host::__wasi_oflags_t {
|
||||
oflags
|
||||
}
|
||||
|
||||
pub fn decode_advice(advice: wasm32::__wasi_advice_t) -> host::__wasi_advice_t {
|
||||
advice
|
||||
}
|
||||
|
||||
pub fn decode_dircookie(dircookie: wasm32::__wasi_dircookie_t) -> host::__wasi_dircookie_t {
|
||||
dircookie
|
||||
}
|
||||
|
||||
pub fn decode_preopentype(preopentype: wasm32::__wasi_preopentype_t) -> host::__wasi_preopentype_t {
|
||||
preopentype
|
||||
}
|
||||
|
||||
pub fn encode_preopentype(preopentype: host::__wasi_preopentype_t) -> wasm32::__wasi_preopentype_t {
|
||||
preopentype
|
||||
}
|
||||
|
||||
pub fn decode_filetype(filetype: wasm32::__wasi_filetype_t) -> host::__wasi_filetype_t {
|
||||
filetype
|
||||
}
|
||||
|
||||
pub fn encode_filetype(filetype: host::__wasi_filetype_t) -> wasm32::__wasi_filetype_t {
|
||||
filetype
|
||||
}
|
||||
|
||||
pub fn decode_fstflags(fstflags: wasm32::__wasi_fstflags_t) -> host::__wasi_fstflags_t {
|
||||
fstflags
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn encode_fstflags(fstflags: host::__wasi_fstflags_t) -> wasm32::__wasi_fstflags_t {
|
||||
fstflags
|
||||
}
|
||||
|
||||
pub fn decode_fdflags(fdflags: wasm32::__wasi_fdflags_t) -> host::__wasi_fdflags_t {
|
||||
fdflags
|
||||
}
|
||||
|
||||
pub fn encode_fdflags(fdflags: host::__wasi_fdflags_t) -> wasm32::__wasi_fdflags_t {
|
||||
fdflags
|
||||
}
|
||||
|
||||
pub fn decode_sdflags(sdflags: wasm32::__wasi_sdflags_t) -> host::__wasi_sdflags_t {
|
||||
sdflags
|
||||
}
|
||||
|
||||
pub fn decode_rights(rights: wasm32::__wasi_rights_t) -> host::__wasi_rights_t {
|
||||
rights
|
||||
}
|
||||
|
||||
pub fn encode_rights(rights: host::__wasi_rights_t) -> wasm32::__wasi_rights_t {
|
||||
rights
|
||||
}
|
||||
|
||||
pub fn decode_riflags(riflags: wasm32::__wasi_riflags_t) -> host::__wasi_riflags_t {
|
||||
riflags
|
||||
}
|
||||
|
||||
pub fn decode_siflags(siflags: wasm32::__wasi_siflags_t) -> host::__wasi_siflags_t {
|
||||
siflags
|
||||
}
|
||||
|
||||
pub unsafe fn decode_char_slice(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: wasm32::size_t,
|
||||
) -> Result<(*mut host::char, usize), host::__wasi_errno_t> {
|
||||
decode_slice_of::<wasm32::char>(vmctx, ptr, len)
|
||||
}
|
||||
|
||||
pub unsafe fn decode_charstar_slice(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
count: wasm32::size_t,
|
||||
) -> Result<(*mut wasm32::uintptr_t, usize), host::__wasi_errno_t> {
|
||||
decode_slice_of::<wasm32::uintptr_t>(vmctx, ptr, count)
|
||||
}
|
||||
|
||||
pub unsafe fn encode_charstar_slice(
|
||||
ptr: *mut wasm32::uintptr_t,
|
||||
host_ptr: *mut *mut libc::c_char,
|
||||
count: usize,
|
||||
guest_base: wasm32::uintptr_t,
|
||||
host_base: *mut libc::c_char,
|
||||
) {
|
||||
for i in 0..count {
|
||||
let host = host_ptr.add(i).read();
|
||||
let guest = if host.is_null() {
|
||||
0
|
||||
} else {
|
||||
guest_base + (host as usize - host_base as usize) as wasm32::uintptr_t
|
||||
};
|
||||
ptr.add(i).write(guest);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn decode_ciovec(
|
||||
vmctx: &mut VMContext,
|
||||
ciovec: &wasm32::__wasi_ciovec_t,
|
||||
) -> Result<host::__wasi_ciovec_t, host::__wasi_errno_t> {
|
||||
let len = cast::usize(ciovec.buf_len);
|
||||
Ok(host::__wasi_ciovec_t {
|
||||
buf: decode_ptr(vmctx, ciovec.buf, len, 1)? as *const host::void,
|
||||
buf_len: len,
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn decode_iovec(
|
||||
vmctx: &mut VMContext,
|
||||
iovec: &wasm32::__wasi_iovec_t,
|
||||
) -> Result<host::__wasi_iovec_t, host::__wasi_errno_t> {
|
||||
let len = cast::usize(iovec.buf_len);
|
||||
Ok(host::__wasi_iovec_t {
|
||||
buf: decode_ptr(vmctx, iovec.buf, len, 1)? as *mut host::void,
|
||||
buf_len: len,
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn decode_ciovec_slice(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: wasm32::size_t,
|
||||
) -> Result<Vec<host::__wasi_ciovec_t>, host::__wasi_errno_t> {
|
||||
let slice = decode_slice_of::<wasm32::__wasi_ciovec_t>(vmctx, ptr, len)?;
|
||||
let slice = slice::from_raw_parts(slice.0, slice.1);
|
||||
slice.iter().map(|iov| decode_ciovec(vmctx, iov)).collect()
|
||||
}
|
||||
|
||||
pub unsafe fn decode_iovec_slice(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: wasm32::size_t,
|
||||
) -> Result<Vec<host::__wasi_iovec_t>, host::__wasi_errno_t> {
|
||||
let slice = decode_slice_of::<wasm32::__wasi_iovec_t>(vmctx, ptr, len)?;
|
||||
let slice = slice::from_raw_parts(slice.0, slice.1);
|
||||
slice.iter().map(|iov| decode_iovec(vmctx, iov)).collect()
|
||||
}
|
||||
|
||||
pub unsafe fn decode_subscription(
|
||||
_vmctx: &mut VMContext,
|
||||
_subscription: wasm32::__wasi_subscription_t,
|
||||
) -> host::__wasi_subscription_t {
|
||||
unimplemented!("decode_subscription");
|
||||
}
|
||||
|
||||
pub unsafe fn decode_subscription_slice(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: wasm32::size_t,
|
||||
) -> Result<Vec<host::__wasi_subscription_t>, host::__wasi_errno_t> {
|
||||
let slice = decode_slice_of::<wasm32::__wasi_subscription_t>(vmctx, ptr, len)?;
|
||||
let slice = slice::from_raw_parts(slice.0, slice.1);
|
||||
Ok(slice
|
||||
.iter()
|
||||
.map(|subscription| decode_subscription(vmctx, *subscription))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub unsafe fn decode_event(
|
||||
_vmctx: &mut VMContext,
|
||||
_event: wasm32::__wasi_event_t,
|
||||
) -> host::__wasi_event_t {
|
||||
unimplemented!("decode_event");
|
||||
}
|
||||
|
||||
pub unsafe fn decode_event_slice(
|
||||
vmctx: &mut VMContext,
|
||||
ptr: wasm32::uintptr_t,
|
||||
len: wasm32::size_t,
|
||||
) -> Result<Vec<host::__wasi_event_t>, host::__wasi_errno_t> {
|
||||
let slice = decode_slice_of::<wasm32::__wasi_event_t>(vmctx, ptr, len)?;
|
||||
let slice = slice::from_raw_parts(slice.0, slice.1);
|
||||
Ok(slice
|
||||
.iter()
|
||||
.map(|event| decode_event(vmctx, *event))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub unsafe fn encode_event_slice(
|
||||
_vmctx: &mut VMContext,
|
||||
_ptr: wasm32::uintptr_t,
|
||||
_host: Vec<host::__wasi_event_t>,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
unimplemented!("encode_event_slice");
|
||||
}
|
||||
|
||||
pub unsafe fn decode_fd_byref(
|
||||
vmctx: &mut VMContext,
|
||||
fd_ptr: wasm32::uintptr_t,
|
||||
) -> Result<host::__wasi_fd_t, host::__wasi_errno_t> {
|
||||
decode_pointee::<wasm32::__wasi_fd_t>(vmctx, fd_ptr).map(decode_fd)
|
||||
}
|
||||
|
||||
pub unsafe fn encode_fd_byref(
|
||||
vmctx: &mut VMContext,
|
||||
fd_ptr: wasm32::uintptr_t,
|
||||
fd: host::__wasi_fd_t,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
encode_pointee::<wasm32::__wasi_fd_t>(vmctx, fd_ptr, wasm32::size_t::cast(fd))
|
||||
}
|
||||
|
||||
pub unsafe fn decode_timestamp_byref(
|
||||
vmctx: &mut VMContext,
|
||||
timestamp_ptr: wasm32::uintptr_t,
|
||||
) -> Result<host::__wasi_timestamp_t, host::__wasi_errno_t> {
|
||||
decode_pointee::<wasm32::__wasi_timestamp_t>(vmctx, timestamp_ptr)
|
||||
.map(host::__wasi_timestamp_t::cast)
|
||||
}
|
||||
|
||||
pub unsafe fn encode_timestamp_byref(
|
||||
vmctx: &mut VMContext,
|
||||
timestamp_ptr: wasm32::uintptr_t,
|
||||
host_timestamp: host::__wasi_timestamp_t,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
encode_pointee::<wasm32::__wasi_timestamp_t>(
|
||||
vmctx,
|
||||
timestamp_ptr,
|
||||
wasm32::__wasi_timestamp_t::cast(host_timestamp),
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn decode_filesize_byref(
|
||||
vmctx: &mut VMContext,
|
||||
filesize_ptr: wasm32::uintptr_t,
|
||||
) -> Result<host::__wasi_filesize_t, host::__wasi_errno_t> {
|
||||
decode_pointee::<wasm32::__wasi_filesize_t>(vmctx, filesize_ptr)
|
||||
.map(host::__wasi_filesize_t::cast)
|
||||
}
|
||||
|
||||
pub unsafe fn encode_filesize_byref(
|
||||
vmctx: &mut VMContext,
|
||||
filesize_ptr: wasm32::uintptr_t,
|
||||
host_filesize: host::__wasi_filesize_t,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
encode_pointee::<wasm32::__wasi_filesize_t>(
|
||||
vmctx,
|
||||
filesize_ptr,
|
||||
wasm32::__wasi_filesize_t::cast(host_filesize),
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn decode_roflags_byref(
|
||||
vmctx: &mut VMContext,
|
||||
roflags_ptr: wasm32::uintptr_t,
|
||||
) -> Result<host::__wasi_roflags_t, host::__wasi_errno_t> {
|
||||
decode_pointee::<wasm32::__wasi_roflags_t>(vmctx, roflags_ptr).map(decode_roflags)
|
||||
}
|
||||
|
||||
pub unsafe fn encode_roflags_byref(
|
||||
vmctx: &mut VMContext,
|
||||
roflags_ptr: wasm32::uintptr_t,
|
||||
host_roflags: host::__wasi_roflags_t,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
encode_pointee::<wasm32::__wasi_roflags_t>(
|
||||
vmctx,
|
||||
roflags_ptr,
|
||||
wasm32::__wasi_roflags_t::cast(host_roflags),
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn decode_usize_byref(
|
||||
vmctx: &mut VMContext,
|
||||
usize_ptr: wasm32::uintptr_t,
|
||||
) -> Result<usize, host::__wasi_errno_t> {
|
||||
decode_pointee::<wasm32::size_t>(vmctx, usize_ptr).map(decode_usize)
|
||||
}
|
||||
|
||||
pub unsafe fn encode_usize_byref(
|
||||
vmctx: &mut VMContext,
|
||||
usize_ptr: wasm32::uintptr_t,
|
||||
host_usize: usize,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
encode_pointee::<wasm32::size_t>(vmctx, usize_ptr, wasm32::size_t::cast(host_usize).unwrap())
|
||||
}
|
||||
|
||||
pub unsafe fn decode_prestat_byref(
|
||||
vmctx: &mut VMContext,
|
||||
prestat_ptr: wasm32::uintptr_t,
|
||||
) -> Result<host::__wasi_prestat_t, host::__wasi_errno_t> {
|
||||
let wasm32_prestat = decode_pointee::<wasm32::__wasi_prestat_t>(vmctx, prestat_ptr)?;
|
||||
|
||||
Ok(host::__wasi_prestat_t {
|
||||
pr_type: decode_preopentype(wasm32_prestat.pr_type),
|
||||
u: host::__wasi_prestat_t___wasi_prestat_u {
|
||||
dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
|
||||
pr_name_len: decode_usize(wasm32_prestat.u.dir.pr_name_len),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn encode_prestat_byref(
|
||||
vmctx: &mut VMContext,
|
||||
prestat_ptr: wasm32::uintptr_t,
|
||||
host_prestat: host::__wasi_prestat_t,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
let wasm32_prestat = wasm32::__wasi_prestat_t {
|
||||
pr_type: encode_preopentype(host_prestat.pr_type),
|
||||
u: wasm32::__wasi_prestat_t___wasi_prestat_u {
|
||||
dir: wasm32::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
|
||||
pr_name_len: encode_usize(host_prestat.u.dir.pr_name_len),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
encode_pointee::<wasm32::__wasi_prestat_t>(vmctx, prestat_ptr, wasm32_prestat)
|
||||
}
|
||||
|
||||
pub unsafe fn decode_fdstat_byref(
|
||||
vmctx: &mut VMContext,
|
||||
fdstat_ptr: wasm32::uintptr_t,
|
||||
) -> Result<host::__wasi_fdstat_t, host::__wasi_errno_t> {
|
||||
let wasm32_fdstat = decode_pointee::<wasm32::__wasi_fdstat_t>(vmctx, fdstat_ptr)?;
|
||||
|
||||
Ok(host::__wasi_fdstat_t {
|
||||
fs_filetype: decode_filetype(wasm32_fdstat.fs_filetype),
|
||||
fs_flags: decode_fdflags(wasm32_fdstat.fs_flags),
|
||||
fs_rights_base: decode_rights(wasm32_fdstat.fs_rights_base),
|
||||
fs_rights_inheriting: decode_rights(wasm32_fdstat.fs_rights_inheriting),
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn encode_fdstat_byref(
|
||||
vmctx: &mut VMContext,
|
||||
fdstat_ptr: wasm32::uintptr_t,
|
||||
host_fdstat: host::__wasi_fdstat_t,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
let wasm32_fdstat = wasm32::__wasi_fdstat_t {
|
||||
fs_filetype: encode_filetype(host_fdstat.fs_filetype),
|
||||
fs_flags: encode_fdflags(host_fdstat.fs_flags),
|
||||
__bindgen_padding_0: 0,
|
||||
fs_rights_base: encode_rights(host_fdstat.fs_rights_base),
|
||||
fs_rights_inheriting: encode_rights(host_fdstat.fs_rights_inheriting),
|
||||
};
|
||||
|
||||
encode_pointee::<wasm32::__wasi_fdstat_t>(vmctx, fdstat_ptr, wasm32_fdstat)
|
||||
}
|
||||
|
||||
pub unsafe fn decode_filestat_byref(
|
||||
_vmctx: &mut VMContext,
|
||||
_filestat_ptr: wasm32::uintptr_t,
|
||||
) -> Result<host::__wasi_filestat_t, host::__wasi_errno_t> {
|
||||
unimplemented!("decode_filestat_byref");
|
||||
}
|
||||
|
||||
pub unsafe fn encode_filestat_byref(
|
||||
_vmctx: &mut VMContext,
|
||||
_filestat_ptr: wasm32::uintptr_t,
|
||||
_host_filestat: host::__wasi_filestat_t,
|
||||
) -> Result<(), host::__wasi_errno_t> {
|
||||
unimplemented!("encode_filestat_byref");
|
||||
}
|
||||
|
||||
pub fn encode_errno(e: host::__wasi_errno_t) -> wasm32::__wasi_errno_t {
|
||||
assert!(e <= wasm32::__WASI_ENOTCAPABLE);
|
||||
e
|
||||
}
|
||||
1286
wasmtime-wasi/src/wasm32.rs
Normal file
1286
wasmtime-wasi/src/wasm32.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user