WASI prototype design, implementation, and documentation.

This adds documents describing the WASI Core API, and an implementation in
Wasmtime.
This commit is contained in:
Dan Gohman
2019-03-27 08:00:00 -07:00
parent b0243b212f
commit b2fefe7714
53 changed files with 12801 additions and 23 deletions

View File

@@ -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]

View File

@@ -14,26 +14,27 @@ utility or as a library embedded in a larger application.
[![Gitter chat](https://badges.gitter.im/CraneStation/CraneStation.svg)](https://gitter.im/CraneStation/Lobby)
![Minimum rustc 1.32](https://img.shields.io/badge/rustc-1.32+-green.svg)
*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

File diff suppressed because it is too large Load Diff

179
docs/WASI-background.md Normal file
View 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
View 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
View 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
View 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
View 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.
![WASI software architecture diagram](wasi-software-architecture.png "WASI software architecture diagram")
## 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

View 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
View 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.

View 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
View 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.

View File

@@ -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> {

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -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"

View File

@@ -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)
}
}

View File

@@ -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
View 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
View 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
View 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
View 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!");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View 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

View 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 */

View 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); \
}); \
");
}

View 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>

View 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);
}
};

View 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 .)

View 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

View 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.

View 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.

View 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

View 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.

View 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

View 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

View 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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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;
}
}

View 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

View 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

View 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

View 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

View 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;
}

View 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

View 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;

View 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
View 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;

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff