`wasi_env_read_stdout` in the C API returns `0` in `lib/c-api/examples/wasi.c`
Opened this issue · 3 comments
gabrielmougard commented
I started to play around with the Wasmer C-API and I simply wanted to run the examples in lib/c-api/examples
I successfully managed to compile the examples but the wasi.c
program seems to not behave properly; here is the output I get when executing it:
$ cd lib/c-api/examples && make run
$ ./wasi
Initializing...
Setting up WASI...
Loading binary...
Compiling module...
Instantiating module...
Extracting export...
found 2 exports
Calling export...
Evaluating "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));"
Call completed
WASI Stdout:
Shutting down...
Done.
Why is the WASI Stdout:
line not showing the Hello, World
mention? It seems that the returned intptr_t
is 0
...
linear commented
syrusakbary commented
This seems like a bug, thanks for reporting it!
FGasper commented
Possibly related: I’ve noticed that, starting in 3.2.0, the following C program shows a return value of 64 and no bytes written. (It works as expected in 3.1.0.)
#include <stdio.h>
#include <wasmer.h>
#include <inttypes.h>
#include <sys/uio.h>
const char *wat_string =
"(module\n"
"(import \"wasi_snapshot_preview1\" \"fd_write\" (func $fdwrite (param i32 i32 i32 i32) (result i32)))\n"
"(memory (export \"memory\") 1)\n"
"(func (export \"fd_write\") (param i32 i32 i32 i32) (result i32)\n"
" local.get 0\n"
" local.get 1\n"
" local.get 2\n"
" local.get 3\n"
" call $fdwrite\n"
")\n"
")";
const char *MESSAGE = "hellohello";
typedef struct {
uint32_t iov_base;
uint32_t iov_len;
} wasi_iovec;
// Use the last_error API to retrieve error messages
void print_wasmer_error()
{
int error_len = wasmer_last_error_length();
if (error_len > 0) {
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);
}
}
void print_frame(wasm_frame_t* frame) {
printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
wasm_frame_instance(frame),
wasm_frame_module_offset(frame),
wasm_frame_func_index(frame),
wasm_frame_func_offset(frame)
);
}
void print_trap(wasm_trap_t* trap) {
printf("Printing message...\n");
wasm_name_t message;
wasm_trap_message(trap, &message);
printf("> %s\n", message.data);
wasm_trap_delete(trap);
}
int main() {
printf("Wasmer version: %s\n", wasmer_version());
//printf("WAT code:\n%s\n", wat_string);
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("Setting up WASI...\n");
wasi_config_t* config = wasi_config_new("example_program");
wasi_config_capture_stdout(config);
wasi_env_t* wasi_env = wasi_env_new(store, config);
if (!wasi_env) {
printf("> Error building WASI env!\n");
print_wasmer_error();
return 1;
}
printf("Instantiating module...\n");
wasm_extern_vec_t imports;
bool 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;
}
wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\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;
}
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("exports: %lu\n", exports.size);
printf("Retrieving the exported memory...\n");
wasm_memory_t* memory = wasm_extern_as_memory(exports.data[0]);
// Observed from an AssemblyScript “Hello, world!”:
const int iovec_offset = 864;
const int payload_offset = 35616;
const int written_offset = 912;
byte_t* memory_buf = wasm_memory_data(memory);
memcpy(memory_buf + payload_offset, MESSAGE, strlen(MESSAGE));
wasi_iovec iovec = {
.iov_base = payload_offset,
.iov_len = strlen(MESSAGE),
};
assert(sizeof(iovec) == 8);
memcpy(memory_buf + iovec_offset, &iovec, sizeof(iovec));
printf("Retrieving the exported function...\n");
wasm_func_t* func = wasm_extern_as_func(exports.data[1]);
if (func == NULL) {
printf("> Failed to get the exported function!\n");
return 1;
}
wasm_val_t args_val[] = {
WASM_I32_VAL(1), //fd
WASM_I32_VAL(iovec_offset),
WASM_I32_VAL(1),
WASM_I32_VAL(written_offset),
};
wasm_val_t results_val[] = { WASM_INIT_VAL };
wasm_val_vec_t args = WASM_ARRAY_VEC(args_val);
wasm_val_vec_t res = WASM_ARRAY_VEC(results_val);
printf("Calling the function...\n-----\n");
wasm_trap_t* trapped = wasm_func_call(func, &args, &res);
if (trapped) {
printf("> Error calling function!\n");
print_trap(trapped);
return 1;
}
printf("\n-----\nCall completed; result=%d\n", results_val[0].of.i32);
uint32_t written;
memcpy(&written, memory_buf + written_offset, sizeof(uint32_t));
printf("Written: %"PRIu32"\n", written);
return 0;
}