wasmer icon indicating copy to clipboard operation
wasmer copied to clipboard

Question about my own imports and WASI using the C API

Open ac000 opened this issue 1 year ago • 1 comments

Summary

Couldn't find a mailing list, so this will have to do...

I have a C WASM module that exports some functions and imports one from the host. This is compiled as --target=wasm32-wasi

It's built against wasi-sysroot-20.0

I have a runtime using wasmtime and it all works fine. Trying to do this also with wasmer (4.0.0 from wasmer-linux-amd64.tar.gz) but am running into the following issue.

I guess I'm trying todo a combination of imports-exports.c & wasi.c

But I keep getting errors about either not finding the WASI import functions or the function I'm importing from the host.

E.g

$ ./wasi 
Initializing...
Setting up WASI...
Loading binary...
Compiling module...
Instantiating module...
> Error instantiating module!
Error len: `139`
Error str: `Error while importing "wasi_snapshot_preview1"."proc_exit": unknown import. Expected Function(FunctionType { params: [I32], results: [] })`
# Change the order I'm doing things
$ ./wasi 
Initializing...
Setting up WASI...
Loading binary...
Compiling module...
WASI version... 2 (SNAPSHOT0)
WASI imports... > Error getting WASI imports!
Error len: `47`
Error str: `Failed to resolve import "env" "imported_func"`

The first error is coming from wasm_instance_new() the second from wasi_get_imports().

I just cannot find a way to appease both.

I've distilled this down to the following.

This runtime is based on the above two mentioned examples.

/*
 * wasi.c
 *
 * Compile with
 *
 * gcc -Wall -Wextra -I../../wasmer-4.0.0/include -L../../wasmer-4.0.0/lib -o wasi wasi.c -lwasmer
 */

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>                                                             
#include <stdbool.h>

#include "wasmer.h"

static wasm_trap_t *imported_func(const wasm_val_vec_t *args,
                                  wasm_val_vec_t *results)
{
        return NULL;
}

static void print_wasmer_error()
{
        int error_len = wasmer_last_error_length();

        if (error_len > 0) {
                char *error_str = malloc(error_len);

                printf("Error len: `%d`\n", error_len);
                wasmer_last_error_message(error_str, error_len);
                printf("Error str: `%s`\n", error_str);
                free(error_str);
        }
}

int main(void)
{
#ifndef WASMER_WASI_ENABLED
#error "No WASI support enabled in wasmer!"
#endif
        wasm_engine_t *engine;
        wasm_store_t *store;
        wasm_module_t *module;
        wasm_instance_t *instance;
        wasm_functype_t *func_ty;
        wasm_func_t *func;
        wasm_extern_t *externs[1];
        wasm_extern_vec_t imports;
        wasm_byte_vec_t binary;
        wasi_config_t *config;
        wasi_env_t *wasi_env;
        wasi_version_t wasi_ver;
        bool get_imports_result;
        FILE *file;
        size_t file_size;
        static const char * const wasi_versions[] = {
                "INVALID_VERSION",
                "LATEST",
                "SNAPSHOT0",
                "SNAPSHOT1",
                "WASIX32V1",
                "WASIX64V1",
        };

        printf("Initializing...\n");
        engine = wasm_engine_new();
        store = wasm_store_new(engine);

        printf("Setting up WASI...\n");
        config = wasi_config_new("example_program");

        wasi_config_inherit_stdin(config);
        wasi_config_inherit_stdout(config);
        wasi_config_inherit_stderr(config);

        printf("Loading binary...\n");
        file = fopen("test.wasm", "r");

        if (!file) {
                printf("> Error loading module!\n");
                return 1;
        }
        fseek(file, 0L, SEEK_END);
        file_size = ftell(file);

        fseek(file, 0L, SEEK_SET);

        wasm_byte_vec_new_uninitialized(&binary, file_size);
        if (fread(binary.data, file_size, 1, file) != 1) {
                printf("> Error initializing module!\n");
                return 1;
        }
        fclose(file);

        printf("Compiling module...\n");
        module = wasm_module_new(store, &binary);

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

        wasm_byte_vec_delete(&binary);

        printf("Instantiating module...\n");
        /* Export a function to the module */
        func_ty = wasm_functype_new_0_0();
        func = wasm_func_new(store, func_ty, imported_func);
        wasm_functype_delete(func_ty);
        *externs = (wasm_extern_t *){ wasm_func_as_extern(func) };
        imports = (wasm_extern_vec_t)WASM_ARRAY_VEC(externs);

        instance = wasm_instance_new(store, module, &imports, NULL);
        if (!instance) {
                printf("> Error instantiating module!\n");
                print_wasmer_error();
                return 1;
        }

        wasi_env = wasi_env_new(store, config);
        if (!wasi_env) {
                printf("> Error building WASI env!\n");
                print_wasmer_error();
                return 1;
        }

        printf("WASI version... ");
        wasi_ver = wasi_get_wasi_version(module);
        printf("%d (%s)\n", wasi_ver, wasi_versions[wasi_ver]);

        printf("WASI imports... ");
        get_imports_result =
            wasi_get_imports(store, wasi_env, module, &imports);
        if (!get_imports_result) {
                printf("> Error getting WASI imports!\n");
                print_wasmer_error();
                return 1;
        }

        if (!wasi_env_initialize_instance(wasi_env, store, instance)) {
                printf("> Error initializing wasi env memory!\n");
                print_wasmer_error();
                return 1;
        }

        wasm_extern_vec_delete(&imports);

        printf("Shutting down...\n");
        wasi_env_delete(wasi_env);
        wasm_module_delete(module);
        wasm_instance_delete(instance);
        wasm_store_delete(store);
        wasm_engine_delete(engine);

        printf("Done.\n");

        return 0;
}

This is a basic WASM module loaded by the above.

/*
 * test.c
 *
 * Compile with:
 *
 * clang -Wall -Wextra --target=wasm32-wasi --sysroot=../../wasi-sysroot -o test.wasm test.c
 */

#include <stdint.h>

typedef uint32_t u32;
typedef uint8_t   u8;

__attribute__((import_module("env"), import_name("imported_func")))
void imported_func(void);

__attribute__((export_name("exported_func")))
int exported_func(u8 *addr, u32 mem_size)
{
        imported_func();
        return 0;
}

int main(void)
{
        return 0;
}

The only reason for the main() function is to make wasi_get_wasi_version() work, not that it's needed. Though I might have expected the reported version to be SNAPSHOT1 given the WASI functions are labelled as wasi_snapshot_preview1... (unless the '1' in SNAPSHOT is not related to the '1' in preview)...

Any pointers in the right direction would be appreciated. Hopefully I'm just missing something obvious...

ac000 avatar Jun 22 '23 20:06 ac000