DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Lauro Moura
Lauro Moura

Posted on

WebAssembly Runtimes - WASI and Wasmtime

After a while (and a release at work), here we are again. To continue the series, we will take a quick look at wasmtime and WASI.

Wasmtime

Wasmtime is a "standalone wasm-only runtime for WebAssembly using the Cranelift JIT". It is part of CraneStation, an "umbrella" project for compiler tools where Mozilla is one (if not the main) parties involved.

The Cranelift JIT is kinda similar to LLVM. Other runtimes like Wasmer - which we will talk about in a future post can switch between Cranelift and LLVM as the backend to generate the code.

But before we go into more wasmtime details, it is important to talk about how we will be interacting with these runtimes.

WASI

As I said in the first post, portability is an important target of WebAssembly. Not only about running a given .wasm file in any place, but also about WebAssembly providing a - as much as possible - portable interface to build programs on top of it. This led to the development of the WebAssembly System Interface - WASI (here is a great post by the great Lin Clark about what is a system interface and why, what, how and who is developing one for WebAssembly).

While system interfaces like POSIX served us well for decades, the challenges of a truly universal system interface in the context of WASM are more strict. This happens because, like a webpage in the browser, you could be running WASM programs from any source and this demands a new approach to security.

WASI thus is being developed with a capability-oriented approach. Instead of the POSIX way of a program inheriting all access rights of the user, in WASI it behaves kinda like installing an app on your phone. Each time a WASM program tries to access a restricted resource, the runtime checks if the user granted access to that resource. We will see more details later in a WASI example.

To begin, we need to install the wasi-sdk that will make it easier for us to create WASI-ready wasm files. It is a clang-based toolchain that is also part of the CraneStation initiative. There are packages available in Github. In my Ubuntu install, the executables were installed to /opt/wasi-sdk/bin. The tutorial for wasi-sdk is here.

Getting wasmtime

The easiest way to get wasmtime is by running their installer with the command below. It will install the runtime to $HOME/.wasmtime/bin and automatically set up the profile scripts to add it to the $PATH when you open a new terminal. Don't forget to re-add the wasi-sdk bin folder to PATH in this new terminal.

$ curl https://wasmtime.dev/install.sh -sSf | bash

As expected a hello world in wasm/wasi is the same as in the desktop:

#include <stdio.h>

int main(void)
{
    printf("Hello, world!\n");
    return 0;
}

To compile, you use the wasi-sdk clang just like you would with a regular C compiler:

$ clang hello.c -o hello.wasm

And to run, just call the wasmtime executable:

$ wasmtime hello.wasm
Hello, World

That's it. You should have the message printed in your terminal. WASI allows the standard output and error descriptors (stdout and stderr) to be freely accessed.

Now, what if we tried to access files? For example, let's implement a cat program. It just reads a file and prints it to the terminal. Save the program below to a file named cat.c.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char* argv[])
{
    if (argc != 2) {
        fprintf(stderr, "usage: %s <input file>\n", argv[0]);
        exit(1);
    }

    int n = 0;
    char buf[BUFSIZ];

    int f = open(argv[1], O_RDONLY);
    if (f < 0) {
        fprintf(stderr, "error opening file %s: %s\n", argv[1], strerror(errno));
        exit(0);
    }

    while((n = read(f, buf, BUFSIZ)) > 0) {
        printf("%.*s", n, buf);
    }

    if (n < 0) {
        fprintf(stderr, "read error: %s\n", strerror(errno));
        exit(0);
    }
    return 0;
}

Like the previous example, compile...

$ clang cat.c -o cat.wasm

And run...

$ wasmtime cat.wasm hello.c
error opening file hello.c: Capabilities insufficient

Ooops. Looks like reading files is a restricted operation. Which makes sense, given files could hold sensitive information. So, how do we grant access to them? With wasmtime, just use the option --dir=<path>:

$ wasmtime --dir=. cat.wasm hello.c
#include <stdio.h>...

Conclusion

This was just a gentle introduction to using wasi-sdk and wasmtime to play with WASI-based Webassembly programs. In the next post, we will see how to embed wasmtime into other programs and do more complex interactions.

Top comments (0)

🌚 Browsing with dark mode makes you a better developer by a factor of exactly 40.

It's a scientific fact.