Giter Club home page Giter Club logo

wac's Introduction

wac - WebAssembly in C

A Minimal WebAssembly interpreter written in C. Supports the WebAssembly MVP (minimum viable product) version of the WebAssembly specification.

There are three different builds of wac:

  • wac: (WebAssembly in C) Minimal client with an interactive REPL mode. Designed to run standalone wasm files compiled with wat2wasm or wasm-as. Passes most spec tests apart from some multi-module import/export tests.
  • wax: (WebAssembly in C with WASI) Client with WebAssembly System Interface APIs (WASI).
  • wace: (WebAssembly in C with Emscripten) Client with host library/memory integration. Designed to run wasm code that has been built with Emscripten (using -s SIDE_MODULE=1 -s LEGALIZE_JS_FFI=0).

Prerequisites

To build wac/wax/wace you need a 32-bit version of gcc and 32-bit versions of SDL2 and libedit. On 64-bit Ubuntu/Debian these can be installed like this:

dpkg --add-architecture i386
apt-get update
apt-get install lib32gcc-4.9-dev libSDL2-dev:i386 libedit-dev:i386

To compile wat source files to binary wasm modules you will need the wasm-as program from Binaryen. To compile C programs to wasm modules you will need Binaryen and emscripten.

As an alternative to downloading and building the above tools, the kanaka/wac docker image (1.7GB) has 32-bit gcc compiler/libraries, emscripten, and binaryen preinstalled. The docker image can be started with appropriate file mounts like this:

docker run -v `pwd`:/wac -w /wac -it kanaka/wac bash

All the build commands below can be run within the docker container.

wac usage

Build wac:

$ make wac

Use wasm-as to compile a simple wat program to a wasm:

$ make examples_wat/arith.wasm

Now load the compiled wasm file and invoke some functions:

$ ./wac examples_wat/arith.wasm add 2 3
0x5:i32
$ ./wac examples_wat/arith.wasm mul 7 8
0x38:i32

wac also supports a very simple REPL (read-eval-print-loop) mode that runs commands in the form of FUNC ARG...:

$ ./wac --repl examples_wat/arith.wasm
> sub 10 5
0x5:i32
> div 13 4
0x3:i32

wax usage

Build wax:

$ make wax

Use wasm-as to compile a wat program that uses the WASI interface:

$ make examples_wat/echo.wasm

Now run the compiled wasm file. The program reads text from stdin and echos it to stdout until an EOF (Ctrl-D) is sent.

$ ./wax examples_wat/echo.wasm
> foo
foo
> bar
bar
> <Ctrl-D>

wace usage

Build wace:

$ make wace

Use emscripten/binaryen to compile some simple C programs and run them using wace:

$ make examples_c/hello1.wasm
$ ./wace examples_c/hello1.wasm
hello world

$ make examples_c/hello2.wasm
$ ./wace examples_c/hello2.wasm
hello malloc people

Use emscripten/binaryen to compile some C SDL programs and run them using wace:

$ make examples_c/hello_sdl.wasm
$ ./wace examples_c/hello_sdl.wasm
INFO: OpenGL shaders: ENABLED
INFO: Created renderer: opengl
# Blue Window displayed for 2 seconds
Done.

$ make examples_c/triangle.wasm
$ ./wace examples_c/triangle.wasm
# A colorfully shaded triangle is rendered

Running WebAssembly spec tests

wac includes a runtest.py test driver which can be used for running tests from the WebAssembly specification.

Check out the spec:

git clone https://github.com/WebAssembly/spec

You will need wat2wasm to compile the spec tests. Check-out and build wabt (wabbit):

git clone --recursive https://github.com/WebAssembly/wabt
make -C wabt gcc-release

Run the func.wast test file (to test function calls) from the spec:

./runtest.py --wat2wasm ./wabt/out/gcc/Release/wat2wasm --interpreter ./wac spec/test/core/func.wast

Run all the spec tests apart from a few that currently fail (mostly due to runtest.py missing support for some syntax used in those test files):

BROKE_TESTS="comments exports imports linking names data elem inline-module"
for t in $(ls spec/test/core/*.wast | grep -Fv "${BROKE_TESTS// /$'\n'}"); do
    echo -e "\nTESTING ${t}"
    ./runtest.py ${t} || break
done

Standalone Builds using Fooboot

wac and wace can be built to run as standalone bootable programs using fooboot:

cd wac
git clone https://github.com/kanaka/fooboot
make PLATFORM=fooboot clean
make PLATFORM=fooboot wac wace examples_wat/addTwo.wasm

The fooboot/runfoo script can be used to boot wac/wace with QEMU. fooboot/runfoo also creates a connection on a serial port (COM2) that allows files to be read from the host system:

fooboot/runfoo wac --repl examples_wat/addTwo.wasm
QEMU waiting for connection on: disconnected:tcp:localhost:21118,server
webassembly> addTwo 2 3
0x5:i32

The standalone wac/wace builds can also be built into an ISO image that can boot directly on real hardware. You will need Grub 2 and the Grub PC/BIOS binary files (grub-pc-bin) and the xorriso program to be able to do this. Also, the wasm modules that you wish to run must be built into the binary to become part of a simple in-memory file-system:

echo "examples_wat/addTwo.wasm" > mem_fs_files
make PLATFORM=fooboot \
     FOO_TARGETS="wac" \
     FOO_CMDLINE="examples_wat/addTwo.wasm addTwo 3 4" \
     boot.iso

You can now boot the ISO with QEMU like this:

qemu-system-i386 -cdrom boot.iso

Or you can burn the ISO to a USB device and boot from it on real hardware. This will destroy any data on the USB device! Also, make completely sure that /dev/MY_USB_DEVICE is really the USB device you want to overwrite and not your hard drive. You have been warned!

sudo dd if=boot.iso of=/dev/MY_USB_DEVICE && sync
# Now boot you can boot from the USB device

License

MPL-2.0 (see LICENSE).

wac's People

Contributors

badboy avatar geky avatar kanaka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wac's Issues

cannot pull kanaka/emscripten from docker hub

I have a bad feeling this is something dumb I'm doing,
but I cannot pull the docker the image.
Things I have tried:
setting the time with ntpdate
reconfiguring tzdata (it threw my clock off by 10min?)
docker pull kanaka/emscripten
sudo docker pull kanaka/emscripten
creating a docker hub account
docker login followed by pull
sudo docker login followed by pull
su to root, docker login, docker pull.

every single time, the downloads finish, but I get 'authentication required'.
I believe my Docker installation is correct- it's from the Jessie repos-
and pulling other images just works:

$ docker pull mono
Using default tag: latest
latest: Pulling from library/mono
5233d9aed181: Already exists 
666418377e5b: Pull complete 
75a87e0601e5: Pull complete 
8e3dafbe502d: Pull complete 
Digest: sha256:32b9d2580388688b8d57742e659f2d021d3d90f036141b1fee81ded64062dd9e
Status: Downloaded newer image for mono:latest

wac crashes

Hi, I did a bit of fuzzing of and found issues that can make wac crash. I provide files to reproduce the issues.

Issue 1: NULL pointer dereference of function

Sample file: https://drive.google.com/open?id=1JnSjtTw6SeKQksgGa2NrzP_syM0bFG82

If a code section is parsed before imports, m->functions can be NULL and will later cause a null pointer dereference. For example:

Block *function = &m->functions[m->import_count+b];

Issue 2: Read out-of-bounds in read functions read_string(), read_LEB, read_uint32.

Sample file: https://drive.google.com/open?id=1yKmr0Om_Ypg1nnz8VPnp5LuQFic2WMLc

The read functions do not make sure that the file has as least the remaining amount of data they attempt to read. For example the read_string functions reads the length of a string in str_len and then memcpy's that length without checking that the remaining file size it at least that long.

char *read_string(uint8_t *bytes, uint32_t *pos, uint32_t *result_len) {
    uint32_t str_len = read_LEB(bytes, pos, 32);
    char * str = malloc(str_len+1);
    memcpy(str, bytes+*pos, str_len);

The read functions should take a bytes_len as a parameter and check the remaining size.

segmentation fault when running clang built wasm

When running wac on sha1sum.wasm from the vmir project, I get the following error:

./wac ~/clones/vmir/examples/prebuilt/sha1sum.wasm
zsh: segmentation fault (core dumped)  ./wac ~/clones/vmir/examples/prebuilt/sha1sum.wasm

I'm using:

  • latest master of wac, commit 1197a2d
  • 64-bit Arch Linux with the official gcc package (gcc 8.1.1)
  • lib32-libedit from AUR

When compiling with -O1 -g and using bt full in gdb, this is the output:

(gdb) r ~/clones/vmir/examples/prebuilt/sha1sum.wasm
Starting program: /home/afr/clones/wac/wac ~/clones/vmir/examples/prebuilt/sha1sum.wasm

Program received signal SIGSEGV, Segmentation fault.
0xf7dae279 in __memset_sse2 () from /usr/lib32/libc.so.6
(gdb) bt full
#0  0xf7dae279 in __memset_sse2 () from /usr/lib32/libc.so.6
No symbol table info available.
#1  0x565655b0 in thunk_out_i_iii (m=0xf7b2d010, function=0x5658b2b8, type=0x5658a6dc) at thunks.c:454
        res = <optimized out>
#2  0x5655fc11 in thunk_out (m=0xf7b2d010, fidx=2) at wa.c:544
        func = 0x5658b2b8
        type = 0x5658a6dc
        thunk_mask = 8454417
        p = <optimized out>
#3  0x565601e3 in interpret (m=0xf7b2d010) at wa.c:809
        block = <optimized out>
        prev_pages = <optimized out>
        sval = <optimized out>
        didx = <optimized out>
        delta = <optimized out>
        bytes = 0xf7fd0000 ""
        stack = 0xf7b2d074
        cur_pc = 492
        block = <optimized out>
        arg = <optimized out>
        val = <optimized out>
        fidx = <optimized out>
        tidx = <optimized out>
        cond = <optimized out>
        depth = <optimized out>
        count = <optimized out>
        flags = <optimized out>
        offset = <optimized out>
        addr = <optimized out>
        maddr = <optimized out>
        mem_end = <optimized out>
        depths = <optimized out>
        opcode = 16 '\020'
        a = <optimized out>
        b = <optimized out>
        c = 4294967104
        d = <optimized out>
        e = <optimized out>
        f = 6221221224307818496
        g = <optimized out>
        h = <optimized out>
        i = -1.03310949e+34
        j = <optimized out>
        k = <optimized out>
        l = 1.3447704791445071e-313
        overflow = false
#4  0x56563be8 in invoke (m=0xf7b2d010, entry=<optimized out>, argc=-1, argv=0xffffd0c0) at wa.c:1997
        fidx = 6
        type = 0x5658a6a0
        result = <optimized out>
#5  0x5655eec7 in main (argc=<optimized out>, argv=<optimized out>) at wac.c:63
        mod_path = <optimized out>
        entry = <optimized out>
        line = <optimized out>
        repl = 0
        debug = 0
        res = 0
        option_index = 0
        c = <optimized out>
        long_options = {{name = 0x5657545c "repl", has_arg = 0, flag = 0xffffcfac, val = 1}, {name = 0x56575461 "debug", has_arg = 0, flag = 0xffffcfb0, val = 1}, {name = 0x0, has_arg = 0, flag = 0x0, val = 0}}
        opts = {disable_memory_bounds = false, mangle_table_index = false, dlsym_trim_underscore = false}
        m = <optimized out>
(gdb)

The problematic line could be line 454 in thunks.c?

examples cannot stat wasm files

running examples in README.md, and each one produces an error similar to:

> root@f2b8deabf964:/wac# ./wace examples_c/hello1.wasm
> Error(platform_libc.c:47): could stat file 'examples_c/hello1.wasm'

Use wast2json instead for generating tests?

wabt provides the wast2json tool to parse the wast files. It then generates a .json file, and a collection of .wasm files for each module. This might be simpler than parsing yourself in runtest.py.

performance?

Hello Kanaka.
I'm inquiring about wac's performance.

Does wac also use a JIT like wasm? If not, how performant is wac as a bytecode interpreter?

Thank You
~Kevin.

Dynamic memory allocation and sandboxing

Hi there,

thank you for sharing your WebAssembly interpreter.
I'm planning to embed WebAssembly in a C++ program so your implementation seems like an excellent starting point.

If I understood the approach correctly, you directly expose C symbols as host imports to the WebAssembly client. This is great for quickly exposing third party libraries like SDL, but what about commands like malloc? Won't these allocate memory in the host's address space rather than the client's linear memory? This does not go well with my idea of isolating the client from the host :)

To completely sandbox the client, I guess it would be necessary to wrap any exported host functions, mapping client to host pointers, and write custom memory management routines.

Do you have any thoughts on this topic?
Do you have further plans with this project, and would you be interested in pull requests in case my fiddling produces something useful?

Cheers,
Martin

-Wformat error

platform_libc.c:18:53: error: format specifies type 'int' but the argument has type 'unsigned long' [-Werror,-Wformat]
        FATAL("Could not allocate %d bytes for %s", (int)nmemb * size, name);
                                  ~~                ^~~~~~~~~~~~~~~~~
                                  %lu
./util.h:20:21: note: expanded from macro 'FATAL'
    fprintf(stderr, __VA_ARGS__); exit(1); \
                    ^~~~~~~~~~~
platform_libc.c:28:53: error: format specifies type 'int' but the argument has type 'unsigned long' [-Werror,-Wformat]
        FATAL("Could not allocate %d bytes for %s", (int)nmemb * size, name);
                                  ~~                ^~~~~~~~~~~~~~~~~
                                  %lu
./util.h:20:21: note: expanded from macro 'FATAL'
    fprintf(stderr, __VA_ARGS__); exit(1); \
                    ^~~~~~~~~~~
2 errors generated.
make: *** [platform_libc.o] Error 1

I can fix the Makefile on my own but you may want to fix this. :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.