diff --git a/core/iwasm/common/gc/gc_type.h b/core/iwasm/common/gc/gc_type.h index 29b171e5a0..10170f0992 100644 --- a/core/iwasm/common/gc/gc_type.h +++ b/core/iwasm/common/gc/gc_type.h @@ -379,6 +379,47 @@ wasm_reftype_set_create(uint32 size); WASMRefType * wasm_reftype_set_insert(HashMap *ref_type_set, const WASMRefType *ref_type); +static inline bool +wasm_val_is_struct(WASMValueWithType *value, const WASMTypePtr *types, + uint32 type_count) +{ + if (!value) { + return false; + } + + if (!wasm_is_type_reftype(value->type)) { + return false; + } + + /* + * WASMStructInitValue and WASMArrayInitValue both use REF_TYPE_HT_NULLABLE + * as their type field. + * if in future, value->type uses other type, need to check more conditions + * here + */ + return wasm_reftype_is_subtype_of(REF_TYPE_HT_NULLABLE, &value->ref_type, + REF_TYPE_STRUCTREF, NULL, types, + type_count); +} + +static inline bool +wasm_val_is_array(WASMValueWithType *value, const WASMTypePtr *types, + uint32 type_count) +{ + if (!value) { + return false; + } + /* + * WASMStructInitValue and WASMArrayInitValue both use REF_TYPE_HT_NULLABLE + * as their type field. + * if in future, value->type uses other type, need to check more conditions + * here + */ + return wasm_reftype_is_subtype_of(REF_TYPE_HT_NULLABLE, &value->ref_type, + REF_TYPE_ARRAYREF, NULL, types, + type_count); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index c60349d10f..50a128d982 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -267,18 +267,6 @@ typedef union WASMValue { } WASMValue; #endif /* end of WASM_VALUE_DEFINED */ -typedef struct WASMStructNewInitValues { - uint32 type_idx; - uint32 count; - WASMValue fields[1]; -} WASMStructNewInitValues; - -typedef struct WASMArrayNewInitValues { - uint32 type_idx; - uint32 length; - WASMValue elem_data[1]; -} WASMArrayNewInitValues; - typedef struct InitializerExpression { /* type of INIT_EXPR_TYPE_XXX, which is an instruction of constant expression */ @@ -528,6 +516,26 @@ typedef struct WASMArrayType { typedef void *WASMString; #endif /* end of WASM_ENABLE_STRINGREF != 0 */ + +typedef struct WASMValueWithType { + /* VALUE_TYPE_XXX or REF_TYPE_XXX*/ + uint8 type; + WASMRefType ref_type; + WASMValue value; +} WASMValueWithType; + +typedef struct WASMStructNewInitValues { + uint32 type_idx; + uint32 count; + WASMValueWithType fields[1]; +} WASMStructNewInitValues; + +typedef struct WASMArrayNewInitValues { + uint32 type_idx; + uint32 length; + WASMValueWithType elem_data[1]; +} WASMArrayNewInitValues; + #endif /* end of WASM_ENABLE_GC != 0 */ typedef struct WASMTableType { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 796b046ed3..6a1da5d047 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -544,48 +544,34 @@ destroy_init_expr_data_recursive(WASMModule *module, void *data) /* The data can only be type of `WASMStructNewInitValues *` or `WASMArrayNewInitValues *` */ - bh_assert(wasm_type->type_flag == WASM_TYPE_STRUCT - || wasm_type->type_flag == WASM_TYPE_ARRAY); + if (wasm_type->type_flag != WASM_TYPE_STRUCT + && wasm_type->type_flag != WASM_TYPE_ARRAY) { + LOG_ERROR("invalid wasm type flag in destroy_init_expr_data_recursive"); + return; + } if (wasm_type->type_flag == WASM_TYPE_STRUCT) { - WASMStructType *struct_type = (WASMStructType *)wasm_type; - WASMRefType *ref_type; - uint8 field_type; - - uint16 ref_type_map_index = 0; for (i = 0; i < struct_init_values->count; i++) { - field_type = struct_type->fields[i].field_type; - if (wasm_is_type_multi_byte_type(field_type)) - ref_type = - struct_type->ref_type_maps[ref_type_map_index++].ref_type; - else - ref_type = NULL; - if (wasm_reftype_is_subtype_of(field_type, ref_type, - REF_TYPE_STRUCTREF, NULL, - module->types, module->type_count) - || wasm_reftype_is_subtype_of( - field_type, ref_type, REF_TYPE_ARRAYREF, NULL, - module->types, module->type_count)) { - destroy_init_expr_data_recursive( - module, struct_init_values->fields[i].data); + WASMValueWithType *field = &struct_init_values->fields[i]; + + if (!wasm_val_is_struct(field, module->types, + module->type_count)) { + continue; } + + destroy_init_expr_data_recursive(module, field->value.data); } } else if (wasm_type->type_flag == WASM_TYPE_ARRAY) { - WASMArrayType *array_type = (WASMArrayType *)wasm_type; - WASMRefType *elem_ref_type = array_type->elem_ref_type; - uint8 elem_type = array_type->elem_type; - for (i = 0; i < array_init_values->length; i++) { - if (wasm_reftype_is_subtype_of(elem_type, elem_ref_type, - REF_TYPE_STRUCTREF, NULL, - module->types, module->type_count) - || wasm_reftype_is_subtype_of( - elem_type, elem_ref_type, REF_TYPE_ARRAYREF, NULL, - module->types, module->type_count)) { - destroy_init_expr_data_recursive( - module, array_init_values->elem_data[i].data); + WASMValueWithType *elem = &array_init_values->elem_data[i]; + + if (!wasm_val_is_array(elem, module->types, + module->type_count)) { + continue; } + + destroy_init_expr_data_recursive(module, elem->value.data); } } @@ -593,12 +579,17 @@ destroy_init_expr_data_recursive(WASMModule *module, void *data) } #endif +/* + * Poo top value from const expr stack, and compare its type with the given declared + * type. If match, return the value and actual ref type(if applicable). + */ static bool pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type, #if WASM_ENABLE_GC != 0 - WASMRefType *ref_type, uint8 *p_gc_opcode, + WASMRefType *declare_ref_type, uint8 *p_gc_opcode, + WASMRefType *p_actual_ref_type, #endif - WASMValue *p_value, + WASMValue *p_value, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 InitializerExpression **p_expr, #endif @@ -621,7 +612,7 @@ pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type, } #else if (!wasm_reftype_is_subtype_of(cur_value->type, &cur_value->ref_type, type, - ref_type, ctx->module->types, + declare_ref_type, ctx->module->types, ctx->module->type_count)) { set_error_buf_v(error_buf, error_buf_size, "%s%s%s", "type mismatch: expect ", type2str(type), @@ -634,6 +625,8 @@ pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type, *p_flag = cur_value->flag; if (p_value) *p_value = cur_value->value; + if (p_actual_ref_type) + *p_actual_ref_type = cur_value->ref_type; #if WASM_ENABLE_GC != 0 if (p_gc_opcode) *p_gc_opcode = cur_value->gc_opcode; @@ -891,7 +884,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, */ if (!(pop_const_expr_stack(&const_expr_ctx, &r_flag, value_type, #if WASM_ENABLE_GC != 0 - NULL, NULL, + NULL, NULL, NULL, #endif &r_value, &r_expr, error_buf, error_buf_size))) { @@ -908,7 +901,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!(pop_const_expr_stack(&const_expr_ctx, &l_flag, value_type, #if WASM_ENABLE_GC != 0 - NULL, NULL, + NULL, NULL, NULL, #endif &l_value, &l_expr, error_buf, error_buf_size))) { @@ -1193,7 +1186,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!(struct_init_values = loader_malloc( offsetof(WASMStructNewInitValues, fields) - + (uint64)field_count * sizeof(WASMValue), + + (uint64)field_count * sizeof(WASMValueWithType), error_buf, error_buf_size))) { goto fail; } @@ -1215,10 +1208,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, field_type = VALUE_TYPE_I32; } + struct_init_values->fields[field_idx].type = field_type; if (!pop_const_expr_stack( &const_expr_ctx, NULL, field_type, - field_ref_type, NULL, - &struct_init_values->fields[field_idx], + field_ref_type, NULL, &struct_init_values->fields[field_idx].ref_type, + &struct_init_values->fields[field_idx].value, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 NULL, #endif @@ -1320,7 +1314,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!pop_const_expr_stack( &const_expr_ctx, NULL, VALUE_TYPE_I32, - NULL, NULL, &len_val, + NULL, NULL, NULL, &len_val, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 NULL, #endif @@ -1342,7 +1336,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!pop_const_expr_stack( &const_expr_ctx, NULL, elem_type, elem_ref_type, NULL, - &array_init_values->elem_data[0], + &array_init_values->elem_data[0].ref_type, + &array_init_values->elem_data[0].value, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 NULL, #endif @@ -1376,8 +1371,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!pop_const_expr_stack( &const_expr_ctx, NULL, elem_type, elem_ref_type, NULL, + &array_init_values->elem_data[i - 1].ref_type, &array_init_values - ->elem_data[i - 1], + ->elem_data[i - 1].value, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 NULL, #endif @@ -1399,7 +1395,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, /* POP(i32) */ if (!pop_const_expr_stack( &const_expr_ctx, NULL, VALUE_TYPE_I32, NULL, - NULL, &len_val, + NULL, NULL, &len_val, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 NULL, #endif @@ -1447,7 +1443,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, { /* POP(i32) */ if (!pop_const_expr_stack(&const_expr_ctx, NULL, - VALUE_TYPE_I32, NULL, NULL, + VALUE_TYPE_I32, NULL, NULL, NULL, &cur_value, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 NULL, @@ -1496,7 +1492,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, /* There should be only one value left on the init value stack */ if (!pop_const_expr_stack(&const_expr_ctx, &flag, type, #if WASM_ENABLE_GC != 0 - ref_type, &opcode, + ref_type, &opcode, NULL, #endif &cur_value, #if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 @@ -1920,6 +1916,11 @@ resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end, if (need_ref_type_map) ref_type_map_count++; + // if (wasm_is_reftype_anyref(ref_type.ref_type)) { + // LOG_ERROR("Not support using anyref in struct fields"); + // return false; + // } + if (wasm_is_type_reftype(ref_type.ref_type)) ref_field_count++; @@ -2039,6 +2040,11 @@ resolve_array_type(const uint8 **p_buf, const uint8 *buf_end, return false; } + if (wasm_is_reftype_anyref(ref_type.ref_type)) { + LOG_ERROR("Not support using anyref in array element type"); + return false; + } + CHECK_BUF(p, p_end, 1); mutable = read_uint8(p); if (!check_mutability(mutable, error_buf, error_buf_size)) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index cac3730bfe..ebef6a29fe 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1050,7 +1050,7 @@ instantiate_struct_global_recursive(WASMModule *module, WASMType *wasm_type; int32 heap_type = ref_type_map->ref_type->ref_ht_common.heap_type; - WASMValue *wasm_value = &init_values->fields[field_idx]; + WASMValue *wasm_value = &init_values->fields[field_idx].value; WASMValue field_value = { 0 }; bh_assert(heap_type >= 0); @@ -1097,7 +1097,7 @@ instantiate_struct_global_recursive(WASMModule *module, } else { wasm_struct_obj_set_field(struct_obj, field_idx, - &init_values->fields[field_idx]); + &init_values->fields[field_idx].value); } if (wasm_is_type_multi_byte_type(field_type)) { ref_type_map++; @@ -1157,7 +1157,7 @@ instantiate_array_global_recursive(WASMModule *module, for (elem_idx = 0; elem_idx < len; elem_idx++) { wasm_array_obj_set_elem(array_obj, elem_idx, - &init_values->elem_data[elem_idx]); + &init_values->elem_data[elem_idx].value); } } @@ -3200,7 +3200,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, len = init_values->length; if (flag == INIT_EXPR_TYPE_ARRAY_NEW_FIXED) { - arr_init_val = init_values->elem_data; + arr_init_val = &init_values->elem_data->value; } } diff --git a/tests/unit/gc/CMakeLists.txt b/tests/unit/gc/CMakeLists.txt index c8b865a384..327825c04c 100644 --- a/tests/unit/gc/CMakeLists.txt +++ b/tests/unit/gc/CMakeLists.txt @@ -11,6 +11,7 @@ set (WAMR_BUILD_GC 1) set (WAMR_BUILD_INTERP 1) set (WAMR_BUILD_AOT 0) set (WAMR_BUILD_APP_FRAMEWORK 0) +set (WAMR_BUILD_SANITIZER "asan") include (../unit_common.cmake) diff --git a/tests/unit/gc/gc_test.cc b/tests/unit/gc/gc_test.cc index 196ddba65a..86e537b718 100644 --- a/tests/unit/gc/gc_test.cc +++ b/tests/unit/gc/gc_test.cc @@ -53,7 +53,7 @@ class WasmGCTest : public testing::Test public: bool load_wasm_file(const char *wasm_file) { - const char *file; + char *file; unsigned char *wasm_file_buf; uint32 wasm_file_size; @@ -61,6 +61,8 @@ class WasmGCTest : public testing::Test wasm_file_buf = (unsigned char *)bh_read_file_to_buffer(file, &wasm_file_size); + free(file); + if (!wasm_file_buf) return false; @@ -100,3 +102,10 @@ TEST_F(WasmGCTest, Test_app1) ASSERT_TRUE(load_wasm_file("func1.wasm")); ASSERT_TRUE(load_wasm_file("func2.wasm")); } + +TEST_F(WasmGCTest, Test_nested_struct) +{ + //FIXME: Revert the change when anyref support is added + ASSERT_FALSE(load_wasm_file("nested_struct_field_any.wasm")); + ASSERT_FALSE(load_wasm_file("nested_array_elem_any.wasm")); +} \ No newline at end of file diff --git a/tests/unit/gc/wasm-apps/nested_array_elem_any.wasm b/tests/unit/gc/wasm-apps/nested_array_elem_any.wasm new file mode 100644 index 0000000000..b241cde58c Binary files /dev/null and b/tests/unit/gc/wasm-apps/nested_array_elem_any.wasm differ diff --git a/tests/unit/gc/wasm-apps/nested_array_elem_any.wat b/tests/unit/gc/wasm-apps/nested_array_elem_any.wat new file mode 100644 index 0000000000..7866ae2547 --- /dev/null +++ b/tests/unit/gc/wasm-apps/nested_array_elem_any.wat @@ -0,0 +1,63 @@ +(module + (type $array_type (array (mut anyref))) + + (global $g_array + (mut (ref $array_type)) + (array.new_fixed $array_type 2 + (ref.i31 (i32.const 10)) + (array.new_fixed $array_type 2 + (ref.i31 (i32.const 20)) + (array.new_default $array_type (i32.const 2)) + ) + ) + ) + + ;; assert_return(invoke "get_elem0"), 10) + (func (export "get_elem0") (result i32) + (i31.get_s (ref.cast i31ref (array.get $array_type (global.get $g_array) (i32.const 0)))) + ) + + ;; assert_return(invoke "get_elem1"), array.new_fixed $array_type ...) + (func (export "get_elem1") (result anyref) + (array.get $array_type (global.get $g_array) (i32.const 1)) + ) + + ;; assert_return(invoke "get_elem1_elem0"), 20) + (func (export "get_elem1_elem0") (result i32) + (i31.get_s (ref.cast i31ref + (array.get $array_type + (ref.cast (ref $array_type) + (array.get $array_type (global.get $g_array) (i32.const 1)) + ) + (i32.const 0) + ) + )) + ) + + ;; assert_return(invoke "get_elem1_elem1"), array.new_default $array_type ...) + (func (export "get_elem1_elem1") (result anyref) + (array.get $array_type + (ref.cast (ref $array_type) + (array.get $array_type (global.get $g_array) (i32.const 1)) + ) + (i32.const 1) + ) + ) + + ;; assert_return(invoke "get_elem1_elem1_elem0"), 0) + (func (export "get_elem1_elem1_elem0") (result i32) + (i31.get_s (ref.cast i31ref + (array.get $array_type + (ref.cast (ref $array_type) + (array.get $array_type + (ref.cast (ref $array_type) + (array.get $array_type (global.get $g_array) (i32.const 1)) + ) + (i32.const 1) + ) + ) + (i32.const 0) + ) + )) + ) +) \ No newline at end of file diff --git a/tests/unit/gc/wasm-apps/nested_struct_field_any.wasm b/tests/unit/gc/wasm-apps/nested_struct_field_any.wasm new file mode 100644 index 0000000000..12c3e2cc71 Binary files /dev/null and b/tests/unit/gc/wasm-apps/nested_struct_field_any.wasm differ diff --git a/tests/unit/gc/wasm-apps/nested_struct_field_any.wat b/tests/unit/gc/wasm-apps/nested_struct_field_any.wat new file mode 100644 index 0000000000..9346373b39 --- /dev/null +++ b/tests/unit/gc/wasm-apps/nested_struct_field_any.wat @@ -0,0 +1,55 @@ +(module + (type $struct_type (struct (field (mut i32)) (field (mut anyref)))) + + (global $g_struct + (mut (ref $struct_type)) + (struct.new $struct_type + (i32.const 10) + (struct.new $struct_type + (i32.const 20) + (struct.new_default $struct_type) + ) + ) + ) + + ;; assert_return(invoke "get_field1"), 10) + (func (export "get_field1") (result i32) + (struct.get $struct_type 0 (global.get $g_struct)) + ) + + ;; assert_return(invoke "get_field1"), struct.new $struct_type ...) + (func (export "get_field2") (result anyref) + (struct.get $struct_type 1 (global.get $g_struct)) + ) + + ;; assert_return(invoke "get_field2_field1"), 20) + (func (export "get_field2_field1") (result i32) + (struct.get $struct_type 0 + (ref.cast structref + (struct.get $struct_type 1 (global.get $g_struct)) + ) + ) + ) + + ;; assert_return(invoke "get_field2_field2"), struct.new_default $struct_type ...) + (func (export "get_field2_field2") (result anyref) + (struct.get $struct_type 1 + (ref.cast structref + (struct.get $struct_type 1 (global.get $g_struct)) + ) + ) + ) + + ;; assert_return(invoke "get_field2_field2_field1"), 0) + (func (export "get_field2_field2_field1") (result i32) + (struct.get $struct_type 0 + (ref.cast structref + (struct.get $struct_type 1 + (ref.cast structref + (struct.get $struct_type 1 (global.get $g_struct)) + ) + ) + ) + ) + ) +)