summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast.c25
-rw-r--r--src/ast.h10
-rw-r--r--src/binary-writer-spec.c23
-rw-r--r--src/resolve-names.c87
-rw-r--r--src/validator.c24
-rw-r--r--test/parse/assert/nocheck-assertinvalid-resolve-names.txt9
6 files changed, 137 insertions, 41 deletions
diff --git a/src/ast.c b/src/ast.c
index d95281f2..301468b8 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -177,6 +177,30 @@ void wasm_make_type_binding_reverse_mapping(
}
}
+void wasm_find_duplicate_bindings(const WasmBindingHash* bindings,
+ WasmDuplicateBindingCallback callback,
+ void* user_data) {
+ size_t i;
+ for (i = 0; i < bindings->entries.capacity; ++i) {
+ WasmBindingHashEntry* entry = &bindings->entries.data[i];
+ if (wasm_hash_entry_is_free(entry))
+ continue;
+
+ /* only follow the chain if this is the first entry in the chain */
+ if (entry->prev != NULL)
+ continue;
+
+ WasmBindingHashEntry* a = entry;
+ for (; a; a = a->next) {
+ WasmBindingHashEntry* b = a->next;
+ for (; b; b = b->next) {
+ if (wasm_string_slices_are_equal(&a->binding.name, &b->binding.name))
+ callback(a, b, user_data);
+ }
+ }
+ }
+}
+
WasmModuleField* wasm_append_module_field(struct WasmAllocator* allocator,
WasmModule* module) {
WasmModuleField* result =
@@ -539,6 +563,7 @@ void wasm_destroy_command(WasmAllocator* allocator, WasmCommand* command) {
wasm_destroy_string_slice(allocator, &command->assert_malformed.text);
break;
case WASM_COMMAND_TYPE_ASSERT_INVALID:
+ case WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY:
wasm_destroy_raw_module(allocator, &command->assert_invalid.module);
wasm_destroy_string_slice(allocator, &command->assert_invalid.text);
break;
diff --git a/src/ast.h b/src/ast.h
index db1b21a9..27844d66 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -330,6 +330,9 @@ typedef enum WasmCommandType {
WASM_COMMAND_TYPE_REGISTER,
WASM_COMMAND_TYPE_ASSERT_MALFORMED,
WASM_COMMAND_TYPE_ASSERT_INVALID,
+ /* This is a module that is invalid, but cannot be written as a binary module
+ * (e.g. it has unresolvable names.) */
+ WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY,
WASM_COMMAND_TYPE_ASSERT_UNLINKABLE,
WASM_COMMAND_TYPE_ASSERT_UNINSTANTIABLE,
WASM_COMMAND_TYPE_ASSERT_RETURN,
@@ -505,6 +508,13 @@ void wasm_make_type_binding_reverse_mapping(
const WasmBindingHash*,
WasmStringSliceVector* out_reverse_mapping);
+typedef void (*WasmDuplicateBindingCallback)(WasmBindingHashEntry* a,
+ WasmBindingHashEntry* b,
+ void* user_data);
+void wasm_find_duplicate_bindings(const WasmBindingHash*,
+ WasmDuplicateBindingCallback callback,
+ void* user_data);
+
static WASM_INLINE WasmBool
wasm_decl_has_func_type(const WasmFuncDeclaration* decl) {
return (WasmBool)((decl->flags & WASM_FUNC_DECLARATION_FLAG_HAS_FUNC_TYPE) !=
diff --git a/src/binary-writer-spec.c b/src/binary-writer-spec.c
index 909b709b..7bd0f29d 100644
--- a/src/binary-writer-spec.c
+++ b/src/binary-writer-spec.c
@@ -139,6 +139,7 @@ static void write_command_type(Context* ctx, const WasmCommand* command) {
"register",
"assert_malformed",
"assert_invalid",
+ NULL, /* ASSERT_INVALID_NON_BINARY, this command will never be written */
"assert_unlinkable",
"assert_uninstantiable",
"assert_return",
@@ -150,6 +151,7 @@ static void write_command_type(Context* ctx, const WasmCommand* command) {
WASM_NUM_COMMAND_TYPES);
write_key(ctx, "type");
+ assert(s_command_names[command->type] != NULL);
write_string(ctx, s_command_names[command->type]);
}
@@ -292,16 +294,13 @@ static void write_action_result_type(Context* ctx,
static void write_module(Context* ctx,
char* filename,
const WasmModule* module) {
- if (!ctx->write_modules)
- return;
-
WasmMemoryWriter writer;
WasmResult result = wasm_init_mem_writer(ctx->allocator, &writer);
if (WASM_SUCCEEDED(result)) {
WasmWriteBinaryOptions options = ctx->spec_options->write_binary_options;
result = wasm_write_binary_module(ctx->allocator, &writer.base, module,
&options);
- if (WASM_SUCCEEDED(result))
+ if (WASM_SUCCEEDED(result) && ctx->write_modules)
result = wasm_write_output_buffer_to_file(&writer.buf, filename);
wasm_close_mem_writer(&writer);
}
@@ -312,12 +311,9 @@ static void write_module(Context* ctx,
static void write_raw_module(Context* ctx,
char* filename,
const WasmRawModule* raw_module) {
- if (!ctx->write_modules)
- return;
-
if (raw_module->type == WASM_RAW_MODULE_TYPE_TEXT) {
write_module(ctx, filename, raw_module->text);
- } else {
+ } else if (ctx->write_modules) {
WasmFileStream stream;
WasmResult result = wasm_init_file_writer(&stream.writer, filename);
if (WASM_SUCCEEDED(result)) {
@@ -354,6 +350,13 @@ static void write_commands(Context* ctx, WasmScript* script) {
for (i = 0; i < script->commands.size; ++i) {
WasmCommand* command = &script->commands.data[i];
+ if (command->type == WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY)
+ continue;
+
+ if (i != 0)
+ write_separator(ctx);
+ wasm_writef(&ctx->json_stream, "\n");
+
wasm_writef(&ctx->json_stream, " {");
write_command_type(ctx, command);
write_separator(ctx);
@@ -459,15 +462,13 @@ static void write_commands(Context* ctx, WasmScript* script) {
write_action(ctx, &command->assert_trap.action);
break;
+ case WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY:
case WASM_NUM_COMMAND_TYPES:
assert(0);
break;
}
wasm_writef(&ctx->json_stream, "}");
- if (i != script->commands.size - 1)
- write_separator(ctx);
- wasm_writef(&ctx->json_stream, "\n");
}
wasm_writef(&ctx->json_stream, "]}\n");
}
diff --git a/src/resolve-names.c b/src/resolve-names.c
index 4b28964c..88c1a0f2 100644
--- a/src/resolve-names.c
+++ b/src/resolve-names.c
@@ -56,34 +56,30 @@ static void pop_label(Context* ctx) {
ctx->labels.size--;
}
+typedef struct FindDuplicateBindingContext {
+ Context* ctx;
+ const char* desc;
+} FindDuplicateBindingContext;
+
+static void on_duplicate_binding(WasmBindingHashEntry* a,
+ WasmBindingHashEntry* b,
+ void* user_data) {
+ FindDuplicateBindingContext* fdbc = user_data;
+ /* choose the location that is later in the file */
+ WasmLocation* a_loc = &a->binding.loc;
+ WasmLocation* b_loc = &b->binding.loc;
+ WasmLocation* loc = a_loc->line > b_loc->line ? a_loc : b_loc;
+ print_error(fdbc->ctx, loc, "redefinition of %s \"" PRIstringslice "\"",
+ fdbc->desc, WASM_PRINTF_STRING_SLICE_ARG(a->binding.name));
+}
+
static void check_duplicate_bindings(Context* ctx,
const WasmBindingHash* bindings,
const char* desc) {
- size_t i;
- for (i = 0; i < bindings->entries.capacity; ++i) {
- WasmBindingHashEntry* entry = &bindings->entries.data[i];
- if (wasm_hash_entry_is_free(entry))
- continue;
-
- /* only follow the chain if this is the first entry in the chain */
- if (entry->prev != NULL)
- continue;
-
- WasmBindingHashEntry* a = entry;
- for (; a; a = a->next) {
- WasmBindingHashEntry* b = a->next;
- for (; b; b = b->next) {
- if (wasm_string_slices_are_equal(&a->binding.name, &b->binding.name)) {
- /* choose the location that is later in the file */
- WasmLocation* a_loc = &a->binding.loc;
- WasmLocation* b_loc = &b->binding.loc;
- WasmLocation* loc = a_loc->line > b_loc->line ? a_loc : b_loc;
- print_error(ctx, loc, "redefinition of %s \"" PRIstringslice "\"",
- desc, WASM_PRINTF_STRING_SLICE_ARG(a->binding.name));
- }
- }
- }
- }
+ FindDuplicateBindingContext fdbc;
+ fdbc.ctx = ctx;
+ fdbc.desc = desc;
+ wasm_find_duplicate_bindings(bindings, on_duplicate_binding, &fdbc);
}
static void resolve_label_var(Context* ctx, WasmVar* var) {
@@ -320,7 +316,6 @@ static void visit_module(Context* ctx, WasmModule* module) {
ctx->current_module = module;
check_duplicate_bindings(ctx, &module->func_bindings, "function");
check_duplicate_bindings(ctx, &module->global_bindings, "global");
- check_duplicate_bindings(ctx, &module->export_bindings, "export");
check_duplicate_bindings(ctx, &module->func_type_bindings, "function type");
check_duplicate_bindings(ctx, &module->table_bindings, "table");
check_duplicate_bindings(ctx, &module->memory_bindings, "memory");
@@ -346,6 +341,13 @@ static void visit_raw_module(Context* ctx, WasmRawModule* raw_module) {
visit_module(ctx, raw_module->text);
}
+void dummy_source_error_callback(const WasmLocation* loc,
+ const char* error,
+ const char* source_line,
+ size_t source_line_length,
+ size_t source_line_column_offset,
+ void* user_data) {}
+
static void visit_command(Context* ctx, WasmCommand* command) {
switch (command->type) {
case WASM_COMMAND_TYPE_MODULE:
@@ -367,9 +369,36 @@ static void visit_command(Context* ctx, WasmCommand* command) {
* assertion is to test for malformed binary modules. */
break;
- case WASM_COMMAND_TYPE_ASSERT_INVALID:
- /* The module may be invalid because the names cannot be resolved (or are
- * duplicates). In either case, don't resolve. */
+ case WASM_COMMAND_TYPE_ASSERT_INVALID: {
+ /* The module may be invalid because the names cannot be resolved; we
+ * don't want to print errors or fail if that's the case, but we still
+ * should try to resolve names when possible. */
+ WasmSourceErrorHandler new_error_handler;
+ new_error_handler.on_error = dummy_source_error_callback;
+ new_error_handler.source_line_max_length =
+ ctx->error_handler->source_line_max_length;
+
+ Context new_ctx;
+ WASM_ZERO_MEMORY(new_ctx);
+ new_ctx.allocator = ctx->allocator;
+ new_ctx.error_handler = &new_error_handler;
+ new_ctx.lexer = ctx->lexer;
+ new_ctx.visitor = ctx->visitor;
+ new_ctx.visitor.user_data = &new_ctx;
+ new_ctx.result = WASM_OK;
+
+ visit_raw_module(&new_ctx, &command->assert_invalid.module);
+ wasm_destroy_label_ptr_vector(new_ctx.allocator, &new_ctx.labels);
+ if (WASM_FAILED(new_ctx.result)) {
+ command->type = WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY;
+ }
+ break;
+ }
+
+ case WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY:
+ /* The only reason a module would be "non-binary" is if the names cannot
+ * be resolved. So we assume name resolution has already been tried and
+ * failed, so skip it. */
break;
case WASM_COMMAND_TYPE_ASSERT_UNLINKABLE:
diff --git a/src/validator.c b/src/validator.c
index d56f09dc..52ca4317 100644
--- a/src/validator.c
+++ b/src/validator.c
@@ -1022,6 +1022,24 @@ static void check_export(Context* ctx, const WasmExport* export_) {
}
}
+static void on_duplicate_binding(WasmBindingHashEntry* a,
+ WasmBindingHashEntry* b,
+ void* user_data) {
+ Context* ctx = user_data;
+ /* choose the location that is later in the file */
+ WasmLocation* a_loc = &a->binding.loc;
+ WasmLocation* b_loc = &b->binding.loc;
+ WasmLocation* loc = a_loc->line > b_loc->line ? a_loc : b_loc;
+ print_error(ctx, loc, "redefinition of export \"" PRIstringslice "\"",
+ WASM_PRINTF_STRING_SLICE_ARG(a->binding.name));
+}
+
+static void check_duplicate_export_bindings(Context* ctx,
+ const WasmModule* module) {
+ wasm_find_duplicate_bindings(&module->export_bindings, on_duplicate_binding,
+ ctx);
+}
+
static void check_module(Context* ctx, const WasmModule* module) {
WasmBool seen_start = WASM_FALSE;
@@ -1097,6 +1115,7 @@ static void check_module(Context* ctx, const WasmModule* module) {
check_elem_segments(ctx, module);
check_data_segments(ctx, module);
+ check_duplicate_export_bindings(ctx, module);
}
typedef struct BinaryErrorCallbackData {
@@ -1274,6 +1293,7 @@ static void check_command(Context* ctx, const WasmCommand* command) {
case WASM_COMMAND_TYPE_REGISTER:
case WASM_COMMAND_TYPE_ASSERT_MALFORMED:
case WASM_COMMAND_TYPE_ASSERT_INVALID:
+ case WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY:
case WASM_COMMAND_TYPE_ASSERT_UNLINKABLE:
case WASM_COMMAND_TYPE_ASSERT_UNINSTANTIABLE:
/* ignore */
@@ -1378,6 +1398,7 @@ WasmResult wasm_validate_assert_invalid_and_malformed(
for (i = 0; i < script->commands.size; ++i) {
WasmCommand* command = &script->commands.data[i];
if (command->type != WASM_COMMAND_TYPE_ASSERT_INVALID &&
+ command->type != WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY &&
command->type != WASM_COMMAND_TYPE_ASSERT_MALFORMED) {
continue;
}
@@ -1389,7 +1410,8 @@ WasmResult wasm_validate_assert_invalid_and_malformed(
ctx2.result = WASM_OK;
ctx2.script = script;
- if (command->type == WASM_COMMAND_TYPE_ASSERT_INVALID) {
+ if (command->type == WASM_COMMAND_TYPE_ASSERT_INVALID ||
+ command->type == WASM_COMMAND_TYPE_ASSERT_INVALID_NON_BINARY) {
ctx2.error_handler = assert_invalid_error_handler;
check_raw_module(&ctx2, &command->assert_invalid.module);
wasm_destroy_context(&ctx2);
diff --git a/test/parse/assert/nocheck-assertinvalid-resolve-names.txt b/test/parse/assert/nocheck-assertinvalid-resolve-names.txt
new file mode 100644
index 00000000..0414d7d2
--- /dev/null
+++ b/test/parse/assert/nocheck-assertinvalid-resolve-names.txt
@@ -0,0 +1,9 @@
+;;; FLAGS: --spec --no-check-assert-invalid
+
+(assert_invalid
+ (module
+ (func
+ block $l
+ br $g
+ end))
+ "foo")