wasmerio / wasmer-c-api

Example of the C API to embed the Wasmer runtime
https://wasmerio.github.io/wasmer/c/runtime-c-api/
80 stars 10 forks source link

C API can't load Wasm binaries with the `wasi_unstable` version #18

Closed helje5 closed 3 years ago

helje5 commented 3 years ago

As per the discussion in the Slack. Wasm modules compiled w/ wasi_unstable do not run w/ the C API. They need to be recompiled from scratch to work. This affects many if not all modules downloaded via wapm as far as I can tell (e.g. cowsay or fortune, qjs etc).

I was able to reproduce this within just this repo.

Steps I took:

Gives:

zMBP20:wasmer-c-api helge$ ./test
Compile result:  2
Error len: `143`
Error str: `Error while importing "wasi_unstable"."fd_prestat_get": unknown import. Expected Function(FunctionType { params: [I32, I32], results: [I32] })`

This is the modified sample:

#include <stdio.h>
#include <wasmer.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>

void print_wasmer_error() {
  int error_len = wasmer_last_error_length();
  printf("Error len: `%d`\n", error_len);
  char *error_str = malloc(error_len);
  wasmer_last_error_message(error_str, error_len);
  printf("Error str: `%s`\n", error_str);
}

int main() {
  // Read the wasm file bytes
  FILE *file = fopen("wasm-wasi-sample-app/program.wasm", "r");
  fseek(file, 0, SEEK_END);
  long len = ftell(file);
  uint8_t *bytes = malloc(len);
  fseek(file, 0, SEEK_SET);
  fread(bytes, 1, len, file);
  fclose(file);

  wasmer_import_object_t *import_object =
    wasmer_wasi_generate_default_import_object();

  wasmer_module_t *module = NULL;
  wasmer_compile(&module, bytes, len);

  wasmer_instance_t *instance = NULL;
  wasmer_result_t compile_result =
    wasmer_module_import_instantiate(&instance, module, import_object);
  printf("Compile result:  %d\n", compile_result);

  if (compile_result != WASMER_OK) {
    print_wasmer_error();
  }
}

It's a little disappointing since being able to run things anywhere is the stated advantage :-)

MarkMcCaskey commented 3 years ago

I believe the default import object generates the latest WASI version:

You can use an older version of WASI with:

Version wasmer_wasi_get_version(const wasmer_module_t *module);

to get the version from the module and

wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(unsigned char version,
                                                                       const wasmer_byte_array *args,
                                                                       unsigned int args_len,
                                                                       const wasmer_byte_array *envs,
                                                                       unsigned int envs_len,
                                                                       const wasmer_byte_array *preopened_files,
                                                                       unsigned int preopened_files_len,
                                                                       const wasmer_wasi_map_dir_entry_t *mapped_dirs,
                                                                       unsigned int mapped_dirs_len);

to get the correct import object.

As an aside, we encourage you to migrate away from the deprecated C API if possible and to the standard Wasm C API wasmer_wasm.h instead.

helje5 commented 3 years ago

Could please mark deprecated API in big letters? E.g. this page mentions nothing about it being deprecated: https://github.com/wasmerio/wasmer-c-api

helje5 commented 3 years ago

Presumably the solution shown here won't work either, because of issue #16 .