From a2343f9f0defc5f0e9a6aa8263c750d84cba4b2e Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 5 Sep 2019 15:08:23 +0200 Subject: [PATCH] test(runtime-c-api) Fully test all kind of exports. --- lib/runtime-c-api/src/export.rs | 16 +- lib/runtime-c-api/tests/assets/exports.rs | 37 ++ lib/runtime-c-api/tests/assets/exports.wasm | Bin 0 -> 262 bytes lib/runtime-c-api/tests/test-exports.c | 508 ++++++++++++++++++-- 4 files changed, 505 insertions(+), 56 deletions(-) create mode 100644 lib/runtime-c-api/tests/assets/exports.rs create mode 100644 lib/runtime-c-api/tests/assets/exports.wasm diff --git a/lib/runtime-c-api/src/export.rs b/lib/runtime-c-api/src/export.rs index e9a770eaa..d6dfa5d97 100644 --- a/lib/runtime-c-api/src/export.rs +++ b/lib/runtime-c-api/src/export.rs @@ -400,15 +400,25 @@ pub unsafe extern "C" fn wasmer_export_func_call( }); return wasmer_result_t::WASMER_ERROR; } - if params.is_null() { + + if params_len > 0 && params.is_null() { update_last_error(CApiError { msg: "params ptr is null".to_string(), }); return wasmer_result_t::WASMER_ERROR; } - let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize); - let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); + let params: Vec = { + if params_len <= 0 { + vec![] + } else { + slice::from_raw_parts::(params, params_len as usize) + .iter() + .cloned() + .map(|x| x.into()) + .collect() + } + }; let named_export = &*(func as *mut NamedExport); diff --git a/lib/runtime-c-api/tests/assets/exports.rs b/lib/runtime-c-api/tests/assets/exports.rs new file mode 100644 index 000000000..9e55985cf --- /dev/null +++ b/lib/runtime-c-api/tests/assets/exports.rs @@ -0,0 +1,37 @@ +#[no_mangle] +pub extern "C" fn sum(x: i32, y: i32) -> i32 { + x + y +} + +#[no_mangle] +pub extern "C" fn arity_0() -> i32 { + 42 +} + +#[no_mangle] +pub extern "C" fn i32_i32(x: i32) -> i32 { + x +} + +#[no_mangle] +pub extern "C" fn i64_i64(x: i64) -> i64 { + x +} + +#[no_mangle] +pub extern "C" fn f32_f32(x: f32) -> f32 { + x +} + +#[no_mangle] +pub extern "C" fn f64_f64(x: f64) -> f64 { + x +} + +#[no_mangle] +pub extern "C" fn string() -> *const u8 { + b"Hello, World!\0".as_ptr() +} + +#[no_mangle] +pub extern "C" fn void() {} diff --git a/lib/runtime-c-api/tests/assets/exports.wasm b/lib/runtime-c-api/tests/assets/exports.wasm new file mode 100644 index 0000000000000000000000000000000000000000..6bea6de33691456004897ea0a06b5f95eb75b0cf GIT binary patch literal 262 zcmZ9`u};G<5C-7??8H}UF?3-L9T7qZ5PLS>fbnb;mm0+lN&-@)w&@e_OgtK{1PjCW z-`zhQ{E!F$E!hE1O%qKH8J!k7(81B3_KtS6(`PeMx+sl8sR;|SP!sB}<2UTz zsq422R%9LgyS(@zXv{?#KY9t9Mw1>s62QKX<5q4#9PjTWgW~x3AQ?2Ta+jgtRqisB zW*Gapd4(xHyV!u|H#0_sir#F2`YK0-|G}t_rx!KI+6(%<&YwctcGuN&*SF2(5AD4+ Apa1{> literal 0 HcmV?d00001 diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index 77ff6683b..f583e8bd3 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -5,81 +5,483 @@ int main() { - // Read the wasm file bytes - FILE *file = fopen("assets/sum.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); + // Read the WebAssembly bytes. + uint8_t *wasm_bytes = NULL; + long wasm_bytes_length = 0; + + { + FILE *file = fopen("assets/exports.wasm", "r"); + fseek(file, 0, SEEK_END); + wasm_bytes_length = ftell(file); + wasm_bytes = (uint8_t *) malloc(wasm_bytes_length); + fseek(file, 0, SEEK_SET); + fread(wasm_bytes, 1, wasm_bytes_length, file); + fclose(file); + } wasmer_import_t imports[] = {}; wasmer_instance_t *instance = NULL; - wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 0); - printf("Compile result: %d\n", compile_result); + wasmer_result_t compile_result = wasmer_instantiate(&instance, wasm_bytes, wasm_bytes_length, imports, 0); + assert(compile_result == WASMER_OK); wasmer_exports_t *exports = NULL; wasmer_instance_exports(instance, &exports); - int exports_len = wasmer_exports_len(exports); - printf("exports_len: %d\n", exports_len); - assert(exports_len == 1); + int exports_length = wasmer_exports_len(exports); + printf("Number of exports: %d\n", exports_length); - wasmer_export_t *export = wasmer_exports_get(exports, 0); + { + printf("\nCheck the `sum` exported function\n"); - wasmer_import_export_kind kind = wasmer_export_kind(export); - assert(kind == WASM_FUNCTION); - const wasmer_export_func_t *func = wasmer_export_to_func(export); + wasmer_export_t *export = wasmer_exports_get(exports, 3); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); - wasmer_byte_array name_bytes = wasmer_export_name(export); - assert(name_bytes.bytes_len == 3); - char expected[] = {'s', 'u', 'm'}; - for(int idx = 0; idx < 3; idx++){ - printf("%c\n", name_bytes.bytes[idx]); - assert(name_bytes.bytes[idx] == expected[idx]); + assert(export_kind == WASM_FUNCTION); + + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + + wasmer_byte_array name_bytes = wasmer_export_name(export); + + assert(name_bytes.bytes_len == 3); + + char expected[] = {'s', 'u', 'm'}; + + printf("Read export name:\n"); + + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + printf("%c\n", name_bytes.bytes[idx]); + + assert(name_bytes.bytes[idx] == expected[idx]); + } + + printf("Check arity\n"); + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 2); + assert(outputs_arity == 1); + + printf("Check signature\n"); + + wasmer_value_tag *input_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * inputs_arity); + wasmer_export_func_params(exported_function, input_types , inputs_arity); + + assert(input_types[0] == WASM_I32); + assert(input_types[1] == WASM_I32); + + free(input_types); + + wasmer_value_tag *output_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * outputs_arity); + wasmer_export_func_returns(exported_function, output_types, outputs_arity); + + assert(output_types[0] == WASM_I32); + + free(output_types); + + printf("Call the exported function\n"); + + wasmer_value_t input_0; + input_0.tag = WASM_I32; + input_0.value.I32 = 7; + + wasmer_value_t input_1; + input_1.tag = WASM_I32; + input_1.value.I32 = 8; + + wasmer_value_t inputs[] = {input_0, input_1}; + + wasmer_value_t output_0; + wasmer_value_t outputs[] = {output_0}; + + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + + printf("Call result: %d\n", call_result); + printf("Result: %d\n", outputs[0].value.I32); + + assert(outputs[0].value.I32 == 15); + assert(call_result == WASMER_OK); } - uint32_t params_arity; - wasmer_export_func_params_arity(func, ¶ms_arity); - assert(params_arity == 2); + { + printf("\nCheck the `arity_0` exported function\n"); - wasmer_value_tag *params_sig = malloc(sizeof(wasmer_value_tag) * params_arity); - wasmer_export_func_params(func, params_sig , params_arity); - assert(params_sig[0] == WASM_I32); - assert(params_sig[1] == WASM_I32); - free(params_sig); + wasmer_export_t *export = wasmer_exports_get(exports, 4); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); - uint32_t returns_arity; - wasmer_export_func_returns_arity(func, &returns_arity); - assert(returns_arity == 1); + assert(export_kind == WASM_FUNCTION); - wasmer_value_tag *returns_sig = malloc(sizeof(wasmer_value_tag) * returns_arity); - wasmer_export_func_returns(func, returns_sig , returns_arity); - assert(returns_sig[0] == WASM_I32); - free(returns_sig); + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + wasmer_byte_array name_bytes = wasmer_export_name(export); - wasmer_value_t param_one; - param_one.tag = WASM_I32; - param_one.value.I32 = 7; - wasmer_value_t param_two; - param_two.tag = WASM_I32; - param_two.value.I32 = 8; - wasmer_value_t params[] = {param_one, param_two}; - wasmer_value_t result_one; - wasmer_value_t results[] = {result_one}; + assert(name_bytes.bytes_len == 7); - wasmer_result_t call_result = wasmer_export_func_call(func, params, params_arity, results, returns_arity); - printf("Call result: %d\n", call_result); - printf("Result: %d\n", results[0].value.I32); - assert(results[0].value.I32 == 15); - assert(call_result == WASMER_OK); + char expected[] = {'a', 'r', 'i', 't', 'y', '_', '0'}; + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + assert(name_bytes.bytes[idx] == expected[idx]); + } + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 0); + assert(outputs_arity == 1); + + wasmer_value_tag *output_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * outputs_arity); + wasmer_export_func_returns(exported_function, output_types, outputs_arity); + + assert(output_types[0] == WASM_I32); + + free(output_types); + + wasmer_value_t inputs[] = {}; + + wasmer_value_t output_0; + wasmer_value_t outputs[] = {output_0}; + + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + + printf("Result: %d\n", outputs[0].value.I32); + + assert(outputs[0].value.I32 == 42); + assert(call_result == WASMER_OK); + } + + { + printf("\nCheck the `i32_i32` exported function\n"); + + wasmer_export_t *export = wasmer_exports_get(exports, 5); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); + + assert(export_kind == WASM_FUNCTION); + + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + wasmer_byte_array name_bytes = wasmer_export_name(export); + + assert(name_bytes.bytes_len == 7); + + char expected[] = {'i', '3', '2', '_', 'i', '3', '2'}; + + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + assert(name_bytes.bytes[idx] == expected[idx]); + } + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 1); + assert(outputs_arity == 1); + + wasmer_value_tag *input_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * inputs_arity); + wasmer_export_func_params(exported_function, input_types , inputs_arity); + + assert(input_types[0] == WASM_I32); + + free(input_types); + + wasmer_value_tag *output_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * outputs_arity); + wasmer_export_func_returns(exported_function, output_types, outputs_arity); + + assert(output_types[0] == WASM_I32); + + free(output_types); + + wasmer_value_t input_0; + input_0.tag = WASM_I32; + input_0.value.I32 = 7; + wasmer_value_t inputs[] = {input_0}; + + wasmer_value_t output_0; + wasmer_value_t outputs[] = {output_0}; + + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + + printf("Result: %d\n", outputs[0].value.I32); + + assert(outputs[0].value.I32 == 7); + assert(call_result == WASMER_OK); + } + + { + printf("\nCheck the `i64_i64` exported function\n"); + + wasmer_export_t *export = wasmer_exports_get(exports, 6); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); + + assert(export_kind == WASM_FUNCTION); + + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + wasmer_byte_array name_bytes = wasmer_export_name(export); + + assert(name_bytes.bytes_len == 7); + + char expected[] = {'i', '6', '4', '_', 'i', '6', '4'}; + + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + assert(name_bytes.bytes[idx] == expected[idx]); + } + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 1); + assert(outputs_arity == 1); + + wasmer_value_tag *input_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * inputs_arity); + wasmer_export_func_params(exported_function, input_types , inputs_arity); + + assert(input_types[0] == WASM_I64); + + free(input_types); + + wasmer_value_tag *output_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * outputs_arity); + wasmer_export_func_returns(exported_function, output_types, outputs_arity); + + assert(output_types[0] == WASM_I64); + + free(output_types); + + wasmer_value_t input_0; + input_0.tag = WASM_I64; + input_0.value.I64 = 7; + wasmer_value_t inputs[] = {input_0}; + + wasmer_value_t output_0; + wasmer_value_t outputs[] = {output_0}; + + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + + printf("Result: %lld\n", outputs[0].value.I64); + + assert(outputs[0].value.I64 == 7); + assert(call_result == WASMER_OK); + } + + { + printf("\nCheck the `f32_f32` exported function\n"); + + wasmer_export_t *export = wasmer_exports_get(exports, 7); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); + + assert(export_kind == WASM_FUNCTION); + + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + wasmer_byte_array name_bytes = wasmer_export_name(export); + + assert(name_bytes.bytes_len == 7); + + char expected[] = {'f', '3', '2', '_', 'f', '3', '2'}; + + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + assert(name_bytes.bytes[idx] == expected[idx]); + } + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 1); + assert(outputs_arity == 1); + + wasmer_value_tag *input_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * inputs_arity); + wasmer_export_func_params(exported_function, input_types , inputs_arity); + + assert(input_types[0] == WASM_F32); + + free(input_types); + + wasmer_value_tag *output_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * outputs_arity); + wasmer_export_func_returns(exported_function, output_types, outputs_arity); + + assert(output_types[0] == WASM_F32); + + free(output_types); + + wasmer_value_t input_0; + input_0.tag = WASM_F32; + input_0.value.F32 = 7.42; + wasmer_value_t inputs[] = {input_0}; + + wasmer_value_t output_0; + wasmer_value_t outputs[] = {output_0}; + + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + + printf("Result: %f\n", outputs[0].value.F32); + + assert(call_result == WASMER_OK); + } + + { + printf("\nCheck the `f64_f64` exported function\n"); + + wasmer_export_t *export = wasmer_exports_get(exports, 8); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); + + assert(export_kind == WASM_FUNCTION); + + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + wasmer_byte_array name_bytes = wasmer_export_name(export); + + assert(name_bytes.bytes_len == 7); + + char expected[] = {'f', '6', '4', '_', 'f', '6', '4'}; + + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + assert(name_bytes.bytes[idx] == expected[idx]); + } + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 1); + assert(outputs_arity == 1); + + wasmer_value_tag *input_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * inputs_arity); + wasmer_export_func_params(exported_function, input_types , inputs_arity); + + assert(input_types[0] == WASM_F64); + + free(input_types); + + wasmer_value_tag *output_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * outputs_arity); + wasmer_export_func_returns(exported_function, output_types, outputs_arity); + + assert(output_types[0] == WASM_F64); + + free(output_types); + + wasmer_value_t input_0; + input_0.tag = WASM_F64; + input_0.value.F64 = 7.42; + wasmer_value_t inputs[] = {input_0}; + + wasmer_value_t output_0; + wasmer_value_t outputs[] = {output_0}; + + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + + printf("Result: %f\n", outputs[0].value.F64); + + assert(call_result == WASMER_OK); + } + + { + printf("\nCheck the `string` exported function\n"); + + wasmer_export_t *export = wasmer_exports_get(exports, 9); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); + + assert(export_kind == WASM_FUNCTION); + + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + wasmer_byte_array name_bytes = wasmer_export_name(export); + + assert(name_bytes.bytes_len == 6); + + char expected[] = {'s', 't', 'r', 'i', 'n', 'g'}; + + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + assert(name_bytes.bytes[idx] == expected[idx]); + } + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 0); + assert(outputs_arity == 1); + + wasmer_value_tag *output_types = (wasmer_value_tag *) malloc(sizeof(wasmer_value_tag) * outputs_arity); + wasmer_export_func_returns(exported_function, output_types, outputs_arity); + + assert(output_types[0] == WASM_I32); + + free(output_types); + + wasmer_value_t inputs[] = {}; + + wasmer_value_t output_0; + wasmer_value_t outputs[] = {output_0}; + + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + + printf("Result: %d\n", outputs[0].value.I32); + + assert(outputs[0].value.I32 == 1048576); + assert(call_result == WASMER_OK); + } + + { + printf("\nCheck the `void` exported function\n"); + + wasmer_export_t *export = wasmer_exports_get(exports, 10); + wasmer_import_export_kind export_kind = wasmer_export_kind(export); + + assert(export_kind == WASM_FUNCTION); + + const wasmer_export_func_t *exported_function = wasmer_export_to_func(export); + wasmer_byte_array name_bytes = wasmer_export_name(export); + + assert(name_bytes.bytes_len == 4); + + char expected[] = {'v', 'o' , 'i', 'd'}; + + for (uint32_t idx = 0; idx < name_bytes.bytes_len; idx++) { + assert(name_bytes.bytes[idx] == expected[idx]); + } + + uint32_t inputs_arity; + wasmer_export_func_params_arity(exported_function, &inputs_arity); + + uint32_t outputs_arity; + wasmer_export_func_returns_arity(exported_function, &outputs_arity); + + assert(inputs_arity == 0); + assert(outputs_arity == 0); + + wasmer_value_t inputs[] = {}; + wasmer_value_t outputs[] = {}; + + { + wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); + assert(call_result == WASMER_OK); + } + + { + wasmer_result_t call_result = wasmer_export_func_call(exported_function, NULL, inputs_arity, NULL, outputs_arity); + assert(call_result == WASMER_OK); + } + } + + printf("\nDestroy instance\n"); - printf("Destroy instance\n"); wasmer_instance_destroy(instance); + printf("Destroy exports\n"); + wasmer_exports_destroy(exports); + return 0; }