Skip to content

Commit

Permalink
Fix most of the spec tests
Browse files Browse the repository at this point in the history
The only ones that are failing are imports, exports, linking and start.

Fixes:
* Make sure to assign loc_ for WasmVar
* Imports must occur before any definition, not just a definition of the
  same kind
* Check that load/store alignment is not larger than natural alignment
* Always check type stack at the end of the check_block; that way an
  empty block is still validated
* Only allow one memory or table, including imports
* Don't allow importing or exporting mutable globals
* Loop label signature is for the fallthrough at the bottom, not the
  branch target. This was implemented properly in the AST checker, but
  not in binary-reader-interpreter
* `top_type_is_any` will check if there is ANY anywhere on the type
  stack; previously this check did not look past the top label's type
  stack limit
* `drop_types_for_return` may be called without having enough values on
  the type stack; for example, at the end of a function the ends with
  return
* properly handle cleaning up the type stack for the interpreter when
  branching to the implicit function label
* rename invoke -> action a few places
  • Loading branch information
binji committed Oct 6, 2016
1 parent a89f67e commit 0ef1b97
Show file tree
Hide file tree
Showing 69 changed files with 2,048 additions and 2,278 deletions.
927 changes: 467 additions & 460 deletions src/prebuilt/wasm-ast-parser-gen.c

Large diffs are not rendered by default.

83 changes: 57 additions & 26 deletions src/wasm-ast-checker.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ static WasmType s_opcode_type2[] = {WASM_FOREACH_OPCODE(V)};
static const char* s_opcode_name[] = {WASM_FOREACH_OPCODE(V)};
#undef V

#define V(rtype, type1, type2, mem_size, code, NAME, text) [code] = mem_size,
static size_t s_opcode_memory_size[] = {WASM_FOREACH_OPCODE(V)};
#undef V

typedef enum CheckStyle {
CHECK_STYLE_NAME,
CHECK_STYLE_FULL,
Expand Down Expand Up @@ -95,6 +99,8 @@ typedef struct Context {
WasmAstLexer* lexer;
const WasmModule* current_module;
const WasmFunc* current_func;
int current_table_index;
int current_memory_index;
int current_global_index;
WasmTypeVector type_stack;
LabelNode* top_label;
Expand All @@ -120,6 +126,12 @@ static WasmBool is_power_of_two(uint32_t x) {
return x && ((x & (x - 1)) == 0);
}

static uint32_t get_opcode_natural_alignment(WasmOpcode opcode) {
uint32_t memory_size = s_opcode_memory_size[opcode];
assert(memory_size != 0);
return memory_size;
}

static void check_duplicate_bindings(Context* ctx,
const WasmBindingHash* bindings,
const char* desc) {
Expand Down Expand Up @@ -283,9 +295,17 @@ static WasmResult check_local_var(Context* ctx,

static void check_align(Context* ctx,
const WasmLocation* loc,
uint32_t alignment) {
if (alignment != WASM_USE_NATURAL_ALIGNMENT && !is_power_of_two(alignment))
print_error(ctx, CHECK_STYLE_FULL, loc, "alignment must be power-of-two");
uint32_t alignment,
uint32_t natural_alignment) {
if (alignment != WASM_USE_NATURAL_ALIGNMENT) {
if (!is_power_of_two(alignment))
print_error(ctx, CHECK_STYLE_FULL, loc, "alignment must be power-of-two");
if (alignment > natural_alignment) {
print_error(ctx, CHECK_STYLE_FULL, loc,
"alignment must not be larger than natural alignment (%u)",
natural_alignment);
}
}
}

static void check_offset(Context* ctx,
Expand Down Expand Up @@ -635,8 +655,8 @@ static void check_block(Context* ctx,
const WasmLocation* loc,
const WasmExpr* first,
const char* desc) {
WasmBool check_result = WASM_TRUE;
if (first) {
WasmBool check_result = WASM_TRUE;
const WasmExpr* expr;
for (expr = first; expr; expr = expr->next) {
check_expr(ctx, expr);
Expand All @@ -646,13 +666,13 @@ static void check_block(Context* ctx,
break;
}
}
if (check_result) {
assert(ctx->top_label != NULL);
check_n_types(ctx, loc, ctx->top_label->sig, desc);
check_type_stack_limit_exact(ctx, loc, ctx->top_label->sig->size, desc);
}
ctx->type_stack.size = ctx->top_label->type_stack_limit;
}
if (check_result) {
assert(ctx->top_label != NULL);
check_n_types(ctx, loc, ctx->top_label->sig, desc);
check_type_stack_limit_exact(ctx, loc, ctx->top_label->sig->size, desc);
}
ctx->type_stack.size = ctx->top_label->type_stack_limit;
}

static void check_expr(Context* ctx, const WasmExpr* expr) {
Expand Down Expand Up @@ -770,7 +790,8 @@ static void check_expr(Context* ctx, const WasmExpr* expr) {
}

case WASM_EXPR_TYPE_LOAD:
check_align(ctx, &expr->loc, expr->load.align);
check_align(ctx, &expr->loc, expr->load.align,
get_opcode_natural_alignment(expr->load.opcode));
check_offset(ctx, &expr->loc, expr->load.offset);
check_opcode1(ctx, &expr->loc, expr->load.opcode);
break;
Expand Down Expand Up @@ -831,7 +852,8 @@ static void check_expr(Context* ctx, const WasmExpr* expr) {
}

case WASM_EXPR_TYPE_STORE:
check_align(ctx, &expr->loc, expr->store.align);
check_align(ctx, &expr->loc, expr->store.align,
get_opcode_natural_alignment(expr->store.opcode));
check_offset(ctx, &expr->loc, expr->store.offset);
check_opcode2(ctx, &expr->loc, expr->store.opcode);
break;
Expand Down Expand Up @@ -1035,6 +1057,8 @@ static void check_limits(Context* ctx,
static void check_table(Context* ctx,
const WasmLocation* loc,
const WasmTable* table) {
if (ctx->current_table_index == 1)
print_error(ctx, CHECK_STYLE_FULL, loc, "only one table allowed");
check_limits(ctx, loc, &table->elem_limits, UINT32_MAX, "elems");
}

Expand Down Expand Up @@ -1080,6 +1104,8 @@ static void check_elem_segments(Context* ctx, const WasmModule* module) {
static void check_memory(Context* ctx,
const WasmLocation* loc,
const WasmMemory* memory) {
if (ctx->current_memory_index == 1)
print_error(ctx, CHECK_STYLE_FULL, loc, "only one memory block allowed");
check_limits(ctx, loc, &memory->page_limits, WASM_MAX_PAGES, "pages");
}

Expand Down Expand Up @@ -1133,12 +1159,18 @@ static void check_import(Context* ctx,
break;
case WASM_EXTERNAL_KIND_TABLE:
check_table(ctx, loc, &import->table);
ctx->current_table_index++;
break;
case WASM_EXTERNAL_KIND_MEMORY:
check_memory(ctx, loc, &import->memory);
ctx->current_memory_index++;
break;
case WASM_EXTERNAL_KIND_GLOBAL:
check_global(ctx, loc, &import->global);
if (import->global.mutable_) {
print_error(ctx, CHECK_STYLE_FULL, loc,
"mutable globals cannot be imported");
}
ctx->current_global_index++;
break;
case WASM_NUM_EXTERNAL_KINDS:
Expand All @@ -1158,21 +1190,28 @@ static void check_export(Context* ctx, const WasmExport* export_) {
case WASM_EXTERNAL_KIND_MEMORY:
check_memory_var(ctx, &export_->var, NULL);
break;
case WASM_EXTERNAL_KIND_GLOBAL:
check_global_var(ctx, &export_->var, NULL, NULL);
case WASM_EXTERNAL_KIND_GLOBAL: {
const WasmGlobal* global;
if (WASM_SUCCEEDED(check_global_var(ctx, &export_->var, &global, NULL))) {
if (global->mutable_) {
print_error(ctx, CHECK_STYLE_FULL, &export_->var.loc,
"mutable globals cannot be exported");
}
}
break;
}
case WASM_NUM_EXTERNAL_KINDS:
assert(0);
break;
}
}

static void check_module(Context* ctx, const WasmModule* module) {
WasmBool seen_memory = WASM_FALSE;
WasmBool seen_table = WASM_FALSE;
WasmBool seen_start = WASM_FALSE;

ctx->current_module = module;
ctx->current_table_index = 0;
ctx->current_memory_index = 0;
ctx->current_global_index = 0;

WasmModuleField* field;
Expand All @@ -1196,25 +1235,17 @@ static void check_module(Context* ctx, const WasmModule* module) {
break;

case WASM_MODULE_FIELD_TYPE_TABLE:
if (seen_table) {
print_error(ctx, CHECK_STYLE_FULL, &field->loc,
"only one table allowed");
}
check_table(ctx, &field->loc, &field->table);
seen_table = WASM_TRUE;
ctx->current_table_index++;
break;

case WASM_MODULE_FIELD_TYPE_ELEM_SEGMENT:
/* checked below */
break;

case WASM_MODULE_FIELD_TYPE_MEMORY:
if (seen_memory) {
print_error(ctx, CHECK_STYLE_FULL, &field->loc,
"only one memory block allowed");
}
check_memory(ctx, &field->loc, &field->memory);
seen_memory = WASM_TRUE;
ctx->current_memory_index++;
break;

case WASM_MODULE_FIELD_TYPE_DATA_SEGMENT:
Expand Down
29 changes: 18 additions & 11 deletions src/wasm-ast-parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
APPEND_FIELD_TO_LIST(module, export_field, EXPORT, export_, loc_, \
(value).export_.export_); \
export_field->export_.kind = WASM_EXTERNAL_KIND_##KIND; \
export_field->export_.var.loc = loc_; \
export_field->export_.var.index = index_; \
APPEND_ITEM_TO_VECTOR(module, Export, export, exports, \
&export_field->export_); \
Expand All @@ -97,13 +98,13 @@
} \
while (0)

#define CHECK_IMPORT_ORDERING(module, kind, kinds, loc_) \
do { \
if ((module)->kinds.size != (module)->num_##kind##_imports) { \
wasm_ast_parser_error(&loc_, lexer, parser, \
"imported " #kind \
" must occur before all defined " #kinds); \
} \
#define CHECK_IMPORT_ORDERING(module, kind, kinds, loc_) \
do { \
if ((module)->kinds.size != (module)->num_##kind##_imports) { \
wasm_ast_parser_error( \
&loc_, lexer, parser, \
"imports must occur before all non-import definitions"); \
} \
} while (0)

#define YYMALLOC(size) wasm_alloc(parser->allocator, size, WASM_DEFAULT_ALIGN)
Expand Down Expand Up @@ -827,11 +828,14 @@ offset :

elem :
LPAR ELEM var offset var_list RPAR {
WASM_ZERO_MEMORY($$);
$$.table_var = $3;
$$.offset = $4.first;
$$.vars = $5;
}
| LPAR ELEM offset var_list RPAR {
WASM_ZERO_MEMORY($$);
$$.table_var.loc = @2;
$$.table_var.type = WASM_VAR_TYPE_INDEX;
$$.table_var.index = 0;
$$.offset = $3.first;
Expand Down Expand Up @@ -867,12 +871,15 @@ table :

data :
LPAR DATA var offset text_list RPAR {
WASM_ZERO_MEMORY($$);
$$.memory_var = $3;
$$.offset = $4.first;
dup_text_list(parser->allocator, &$5, &$$.data, &$$.size);
wasm_destroy_text_list(parser->allocator, &$5);
}
| LPAR DATA offset text_list RPAR {
WASM_ZERO_MEMORY($$);
$$.memory_var.loc = @2;
$$.memory_var.type = WASM_VAR_TYPE_INDEX;
$$.memory_var.index = 0;
$$.offset = $3.first;
Expand Down Expand Up @@ -1182,34 +1189,34 @@ module_fields :
$$ = $1;
WasmModuleField* field;
APPEND_FIELD_TO_LIST($$, field, IMPORT, import, @2, *$2);
CHECK_IMPORT_ORDERING($$, func, funcs, @2);
CHECK_IMPORT_ORDERING($$, table, tables, @2);
CHECK_IMPORT_ORDERING($$, memory, memories, @2);
CHECK_IMPORT_ORDERING($$, global, globals, @2);
switch ($2->kind) {
case WASM_EXTERNAL_KIND_FUNC:
append_implicit_func_declaration(parser->allocator, &@2, $$,
&field->import.func.decl);
APPEND_ITEM_TO_VECTOR($$, Func, func, funcs, &field->import.func);
INSERT_BINDING($$, func, funcs, @2, field->import.func.name);
$$->num_func_imports++;
CHECK_IMPORT_ORDERING($$, func, funcs, @2);
break;
case WASM_EXTERNAL_KIND_TABLE:
APPEND_ITEM_TO_VECTOR($$, Table, table, tables, &field->import.table);
INSERT_BINDING($$, table, tables, @2, field->import.table.name);
$$->num_table_imports++;
CHECK_IMPORT_ORDERING($$, table, tables, @2);
break;
case WASM_EXTERNAL_KIND_MEMORY:
APPEND_ITEM_TO_VECTOR($$, Memory, memory, memories,
&field->import.memory);
INSERT_BINDING($$, memory, memories, @2, field->import.memory.name);
$$->num_memory_imports++;
CHECK_IMPORT_ORDERING($$, memory, memories, @2);
break;
case WASM_EXTERNAL_KIND_GLOBAL:
APPEND_ITEM_TO_VECTOR($$, Global, global, globals,
&field->import.global);
INSERT_BINDING($$, global, globals, @2, field->import.global.name);
$$->num_global_imports++;
CHECK_IMPORT_ORDERING($$, global, globals, @2);
break;
case WASM_NUM_EXTERNAL_KINDS:
assert(0);
Expand Down
2 changes: 2 additions & 0 deletions src/wasm-ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,8 @@ static void destroy_module_field(WasmAllocator* allocator,
}

void wasm_destroy_module(WasmAllocator* allocator, WasmModule* module) {
wasm_destroy_string_slice(allocator, &module->name);

WasmModuleField* field = module->first_field;
while (field != NULL) {
WasmModuleField* next_field = field->next;
Expand Down
Loading

0 comments on commit 0ef1b97

Please sign in to comment.