Files
wasmer/lib/c-api
Ivan Enderlin eea75e7862 fix(c-api) Trap's messages are always null terminated.
`wasm_trap_new` expects a `wasm_message_t`. It's a type alias to
`wasm_name_t` with the exception that it represents a null-terminated
string.

When calling `wasm_trap_new`, no check was present to ensure the
string was well-formed. That's a first issue. But in the best
scenario, the string was correctly formed and was
null-terminated. This string was transformed to a Rust `String` —with
the null byte!— and passed to `RuntimeError`.

Then in `wasm_trap_message`, another null byte was pushed at the end
of the message. It's been introduced in
https://github.com/wasmerio/wasmer/pull/1947. It results in a
doubly-null-terminated string, which is incorrect.

This patch does the following:

1. It checks that the string given to `wasm_trap_new` contains a
   null-terminated string or not, and will act accordingly. Note that
   it's possible to pass a non-null-terminated string, and it will
   still work because this detail is vicious. The idea is to get a
   well-formed `RuntimeError` in anycase.

  * If no null byte is found, the string is passed to `RuntimeError`
    as a valid Rust string,

  * If a null byte is found at the end of the string, a new string is
    passed to `RuntimeError` but without the final null byte,

  * If a null byte is found but not at the end, it's considered as an
    error,

  * If the string contains invalid UTF-8 bytes, it's considered as an
    error.

2. It updates `wasm_trap_message` to always add a null byte at the end
   of the returned owned string.

3. It adds test cases when passing a null-terminated or a
   non-null-terminated string to `wasm_trap_new` and to compare the
   results to `wasm_trap_message`.
2021-06-25 11:42:04 +02:00
..
2021-06-01 21:47:37 -07:00
2020-09-22 09:44:11 +02:00
2021-06-01 21:47:37 -07:00
2021-06-15 11:26:46 -07:00
2020-12-04 13:39:44 -08:00
2021-06-15 11:26:46 -07:00

wasmer-c-api Build Status Join Wasmer Slack MIT License

This crate exposes a C and a C++ API for the Wasmer runtime. It also fully supports the wasm-c-api common API.

Usage

Once you install Wasmer in your system, the shared object files and the headers are available inside the Wasmer installed path.

$WASMER_DIR/
  lib/
    libwasmer.{so,dylib,dll}
  include/
    wasm.h
    wasmer.h
    wasmer.hh
    wasmer.h

Wasmer binary also ships with wasmer-config an utility tool that outputs config information needed to compile programs which use Wasmer.

The full C API documentation can be found here: https://wasmerio.github.io/wasmer/crates/wasmer_c_api/index.html

Here is a simple example to use the C API:

#include <stdio.h>
#include "wasmer.h"

int main(int argc, const char* argv[]) {
    const char *wat_string =
        "(module\n"
        "  (type $sum_t (func (param i32 i32) (result i32)))\n"
        "  (func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)\n"
        "    local.get $x\n"
        "    local.get $y\n"
        "    i32.add)\n"
        "  (export \"sum\" (func $sum_f)))";

    wasm_byte_vec_t wat;
    wasm_byte_vec_new(&wat, strlen(wat_string), wat_string);
    wasm_byte_vec_t wasm_bytes;
    wat2wasm(&wat, &wasm_bytes);
    wasm_byte_vec_delete(&wat);

    printf("Creating the store...\n");
    wasm_engine_t* engine = wasm_engine_new();
    wasm_store_t* store = wasm_store_new(engine);

    printf("Compiling module...\n");
    wasm_module_t* module = wasm_module_new(store, &wasm_bytes);

    if (!module) {
        printf("> Error compiling module!\n");
        return 1;
    }

    wasm_byte_vec_delete(&wasm_bytes);

    printf("Creating imports...\n");
    wasm_extern_vec_t import_object = WASM_EMPTY_VEC;

    printf("Instantiating module...\n");
    wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL);

    if (!instance) {
      printf("> Error instantiating module!\n");
      return 1;
    }

    printf("Retrieving exports...\n");
    wasm_extern_vec_t exports;
    wasm_instance_exports(instance, &exports);

    if (exports.size == 0) {
        printf("> Error accessing exports!\n");
        return 1;
    }

    printf("Retrieving the `sum` function...\n");
    wasm_func_t* sum_func = wasm_extern_as_func(exports.data[0]);

    if (sum_func == NULL) {
        printf("> Failed to get the `sum` function!\n");
        return 1;
    }

    printf("Calling `sum` function...\n");
    wasm_val_t args_val[2] = { WASM_I32_VAL(3), WASM_I32_VAL(4) };
    wasm_val_t results_val[1] = { WASM_INIT_VAL };
    wasm_val_vec_t args = WASM_ARRAY_VEC(args_val);
    wasm_val_vec_t results = WASM_ARRAY_VEC(results_val);

    if (wasm_func_call(sum_func, &args, &results)) {
        printf("> Error calling the `sum` function!\n");

        return 1;
    }

    printf("Results of `sum`: %d\n", results_val[0].of.i32);

    wasm_func_delete(sum_func);
    wasm_module_delete(module);
    wasm_extern_vec_delete(&exports);
    wasm_instance_delete(instance);
    wasm_store_delete(store);
    wasm_engine_delete(engine);
}

Building

You can compile Wasmer shared library from source:

make build-capi

This will generate the shared library (depending on your system):

  • Windows: target/release/libwasmer_c_api.dll
  • macOS: target/release/libwasmer_runtime_c_api.dylib
  • Linux: target/release/libwasmer_runtime_c_api.so

If you want to generate the library and headers in a friendly format as shown in Usage, you can execute the following in Wasmer root:

make package-capi

This command will generate a package directory, that you can then use easily in the Wasmer C API examples.

Testing

Tests are run using the release build of the library. If you make changes or compile with non-default features, please ensure you rebuild in release mode for the tests to see the changes.

To run all the full suite of tests, enter Wasmer root directory and run the following commands:

$ make test-capi

wasmer config

wasmer config output various configuration information needed to compile programs which use Wasmer.

wasmer config --pkg-config

It outputs the necessary details for compiling and linking a program to Wasmer, using the pkg-config format:

$ wasmer config --pkg-config > $PKG_CONFIG_PATH/wasmer.pc

wasmer config --includedir

Directory containing Wasmer headers:

$ wasmer config --includedir
/users/myuser/.wasmer/include

wasmer config --libdir

Directory containing Wasmer libraries:

$ wasmer config --libdir
/users/myuser/.wasmer/lib

wasmer config --libs

Libraries needed to link against Wasmer components:

$ wasmer config --libs
-L/Users/myuser/.wasmer/lib -lwasmer

wasmer config --libs

Libraries needed to link against Wasmer components:

$ wasmer config --cflags
-I/Users/myuser/.wasmer/include/wasmer

License

Wasmer is primarily distributed under the terms of the MIT license (LICENSE).