diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 56e508104d..e071c5c8df 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -206,6 +206,7 @@ class WastParser { ReferenceVars*, Errors*); Result ParseModuleFieldList(Module*); Result ParseModuleField(Module*); + Result ParseModuleFieldImpl(Module*); Result ParseDataModuleField(Module*); Result ParseElemModuleField(Module*); Result ParseTagModuleField(Module*); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 78b05eebdb..9272de391b 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1494,6 +1494,31 @@ Result WastParser::ParseModuleFieldList(Module* module) { Result WastParser::ParseModuleField(Module* module) { WABT_TRACE(ParseModuleField); + // A field is only appended to the module once it has parsed successfully; a + // field that fails to parse is destroyed instead, so the deferred reference + // type resolutions registered while parsing it would point into freed + // memory. Remember where the resolve lists ended and drop those entries + // again if the field fails. + size_t ref_types_size = resolve_ref_types_.size(); + size_t type_vectors_size = resolve_type_vectors_.size(); + size_t funcs_size = resolve_funcs_.size(); + + Result result = ParseModuleFieldImpl(module); + + if (Failed(result)) { + resolve_ref_types_.erase(resolve_ref_types_.begin() + ref_types_size, + resolve_ref_types_.end()); + resolve_type_vectors_.erase( + resolve_type_vectors_.begin() + type_vectors_size, + resolve_type_vectors_.end()); + resolve_funcs_.erase(resolve_funcs_.begin() + funcs_size, + resolve_funcs_.end()); + } + + return result; +} + +Result WastParser::ParseModuleFieldImpl(Module* module) { switch (Peek(1)) { case TokenType::Data: return ParseDataModuleField(module); case TokenType::Elem: return ParseElemModuleField(module); diff --git a/test/parse/bad-ref-type-in-failed-field.txt b/test/parse/bad-ref-type-in-failed-field.txt new file mode 100644 index 0000000000..5e0c2ab893 --- /dev/null +++ b/test/parse/bad-ref-type-in-failed-field.txt @@ -0,0 +1,37 @@ +;;; TOOL: wat2wasm +;;; ARGS: --enable-function-references +;;; ERROR: 1 +(module + (type $t (func)) + + ;; Each field below names a reference type, which defers its resolution to + ;; the end of the module, and then fails to parse. + (func (param (ref $t)) (foo)) + (func (result (ref null $t)) (foo)) + (func (local (ref $t)) (foo)) + (table 0 (ref null $t) (foo)) + (elem declare (ref null $t) (item ref.null $t) foo) + (import "a" "b" (func (param (ref $t)) foo)) + + (memory 1) +) +(;; STDERR ;;; +out/test/parse/bad-ref-type-in-failed-field.txt:9:27: error: unexpected token "foo", expected an instr. + (func (param (ref $t)) (foo)) + ^^^ +out/test/parse/bad-ref-type-in-failed-field.txt:10:33: error: unexpected token "foo", expected an instr. + (func (result (ref null $t)) (foo)) + ^^^ +out/test/parse/bad-ref-type-in-failed-field.txt:11:27: error: unexpected token "foo", expected an instr. + (func (local (ref $t)) (foo)) + ^^^ +out/test/parse/bad-ref-type-in-failed-field.txt:12:27: error: unexpected token "foo", expected an instr. + (table 0 (ref null $t) (foo)) + ^^^ +out/test/parse/bad-ref-type-in-failed-field.txt:13:50: error: unexpected token foo, expected ). + (elem declare (ref null $t) (item ref.null $t) foo) + ^^^ +out/test/parse/bad-ref-type-in-failed-field.txt:14:42: error: unexpected token foo, expected ). + (import "a" "b" (func (param (ref $t)) foo)) + ^^^ +;;; STDERR ;;)