diff options
author | Ben Smith <binjimin@gmail.com> | 2017-09-12 16:30:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-12 16:30:49 -0700 |
commit | a4aa20105bc8851b57b50b5c62684c0f36cdbb02 (patch) | |
tree | 735c09a2f4f49285ed1791f1baefc125907be540 | |
parent | caf98190ca5267a0864ef019889b31ed16d95f77 (diff) | |
download | wabt-a4aa20105bc8851b57b50b5c62684c0f36cdbb02.tar.gz wabt-a4aa20105bc8851b57b50b5c62684c0f36cdbb02.tar.bz2 wabt-a4aa20105bc8851b57b50b5c62684c0f36cdbb02.zip |
Only allow parsing one module with wat2wasm (#622)
`.wat` files can only contain one module, and no assertions.
This fixes issue #621.
-rw-r--r-- | src/emscripten-helpers.cc | 2 | ||||
-rw-r--r-- | src/tools/wasm-interp.cc | 2 | ||||
-rw-r--r-- | src/tools/wast-desugar.cc | 4 | ||||
-rw-r--r-- | src/tools/wast2json.cc | 4 | ||||
-rw-r--r-- | src/tools/wat2wasm.cc | 17 | ||||
-rw-r--r-- | src/wast-parser.cc | 90 | ||||
-rw-r--r-- | src/wast-parser.h | 24 | ||||
-rw-r--r-- | test/parse/bad-crlf.txt | 2 | ||||
-rw-r--r-- | test/parse/bad-error-long-line.txt | 2 | ||||
-rw-r--r-- | test/parse/bad-error-long-token.txt | 2 | ||||
-rw-r--r-- | test/parse/bad-single-semicolon.txt | 2 | ||||
-rw-r--r-- | test/parse/bad-toplevel.txt | 2 | ||||
-rw-r--r-- | test/parse/empty-file.txt | 2 | ||||
-rw-r--r-- | test/parse/module/bad-module-multi.txt | 10 | ||||
-rw-r--r-- | test/parse/module/bad-module-with-assert.txt | 10 |
15 files changed, 119 insertions, 56 deletions
diff --git a/src/emscripten-helpers.cc b/src/emscripten-helpers.cc index 48513fdd..9b0f1117 100644 --- a/src/emscripten-helpers.cc +++ b/src/emscripten-helpers.cc @@ -66,7 +66,7 @@ WabtParseWastResult* wabt_parse_wast(wabt::WastLexer* lexer, wabt::ErrorHandlerBuffer* error_handler) { WabtParseWastResult* result = new WabtParseWastResult(); std::unique_ptr<wabt::Script> script; - result->result = wabt::ParseWast(lexer, &script, error_handler); + result->result = wabt::ParseWastScript(lexer, &script, error_handler); result->script = std::move(script); return result; } diff --git a/src/tools/wasm-interp.cc b/src/tools/wasm-interp.cc index 5c108405..12fdae04 100644 --- a/src/tools/wasm-interp.cc +++ b/src/tools/wasm-interp.cc @@ -1014,7 +1014,7 @@ wabt::Result SpecJSONParser::ReadInvalidTextModule( std::unique_ptr<WastLexer> lexer = WastLexer::CreateFileLexer(module_filename); std::unique_ptr<Script> script; - wabt::Result result = ParseWast(lexer.get(), &script, error_handler); + wabt::Result result = ParseWastScript(lexer.get(), &script, error_handler); if (Succeeded(result)) { wabt::Module* module = script->GetFirstModule(); result = ResolveNamesModule(lexer.get(), module, error_handler); diff --git a/src/tools/wast-desugar.cc b/src/tools/wast-desugar.cc index 03bdc4b8..8aa76af8 100644 --- a/src/tools/wast-desugar.cc +++ b/src/tools/wast-desugar.cc @@ -88,8 +88,8 @@ int ProgramMain(int argc, char** argv) { ErrorHandlerFile error_handler(Location::Type::Text); std::unique_ptr<Script> script; WastParseOptions parse_wast_options(s_features); - Result result = - ParseWast(lexer.get(), &script, &error_handler, &parse_wast_options); + Result result = ParseWastScript(lexer.get(), &script, &error_handler, + &parse_wast_options); if (Succeeded(result)) { Module* module = script->GetFirstModule(); diff --git a/src/tools/wast2json.cc b/src/tools/wast2json.cc index 7fb75c72..c13221dd 100644 --- a/src/tools/wast2json.cc +++ b/src/tools/wast2json.cc @@ -101,8 +101,8 @@ int ProgramMain(int argc, char** argv) { ErrorHandlerFile error_handler(Location::Type::Text); std::unique_ptr<Script> script; WastParseOptions parse_wast_options(s_features); - Result result = - ParseWast(lexer.get(), &script, &error_handler, &parse_wast_options); + Result result = ParseWastScript(lexer.get(), &script, &error_handler, + &parse_wast_options); if (Succeeded(result)) { result = ResolveNamesScript(lexer.get(), script.get(), &error_handler); diff --git a/src/tools/wat2wasm.cc b/src/tools/wat2wasm.cc index 20e27908..2eb63a42 100644 --- a/src/tools/wat2wasm.cc +++ b/src/tools/wat2wasm.cc @@ -123,26 +123,21 @@ int ProgramMain(int argc, char** argv) { WABT_FATAL("unable to read file: %s\n", s_infile); ErrorHandlerFile error_handler(Location::Type::Text); - // TODO(binji): Parse Module instead of Script. - std::unique_ptr<Script> script; + std::unique_ptr<Module> module; WastParseOptions parse_wast_options(s_features); Result result = - ParseWast(lexer.get(), &script, &error_handler, &parse_wast_options); + ParseWatModule(lexer.get(), &module, &error_handler, &parse_wast_options); if (Succeeded(result)) { - result = ResolveNamesScript(lexer.get(), script.get(), &error_handler); + result = ResolveNamesModule(lexer.get(), module.get(), &error_handler); if (Succeeded(result) && s_validate) - result = ValidateScript(lexer.get(), script.get(), &error_handler); + result = ValidateModule(lexer.get(), module.get(), &error_handler); if (Succeeded(result)) { MemoryStream stream(s_log_stream.get()); - const Module* module = script->GetFirstModule(); - if (module) { - result = WriteBinaryModule(&stream, module, &s_write_binary_options); - } else { - WABT_FATAL("no module found\n"); - } + result = + WriteBinaryModule(&stream, module.get(), &s_write_binary_options); if (Succeeded(result)) WriteBufferToFile(s_outfile, stream.output_buffer()); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 3048cee2..a9a53973 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -630,9 +630,37 @@ Result WastParser::ParseNat(uint64_t* out_nat) { return Result::Ok; } -Result WastParser::ParseScript() { +Result WastParser::ParseModule(std::unique_ptr<Module>* out_module) { + WABT_TRACE(ParseModule); + auto module = MakeUnique<Module>(); + + if (PeekMatchLpar(TokenType::Module)) { + // Starts with "(module". Allow text and binary modules, but no quoted + // modules. + CommandPtr command; + CHECK_RESULT(ParseModuleCommand(nullptr, &command)); + auto module_command = cast<ModuleCommand>(std::move(command)); + *module = std::move(module_command->module); + } else if (IsModuleField(PeekPair())) { + // Parse an inline module (i.e. one with no surrounding (module)). + CHECK_RESULT(ParseModuleFieldList(module.get())); + } else { + ConsumeIfLpar(); + ErrorExpected({"a module field", "a module"}); + } + + EXPECT(Eof); + if (errors_ == 0) { + *out_module = std::move(module); + return Result::Ok; + } else { + return Result::Error; + } +} + +Result WastParser::ParseScript(std::unique_ptr<Script>* out_script) { WABT_TRACE(ParseScript); - script_ = MakeUnique<Script>(); + auto script = MakeUnique<Script>(); // Don't consume the Lpar yet, even though it is required. This way the // sub-parser functions (e.g. ParseFuncModuleField) can consume it and keep @@ -642,16 +670,21 @@ Result WastParser::ParseScript() { auto command = MakeUnique<ModuleCommand>(); command->module.loc = GetLocation(); CHECK_RESULT(ParseModuleFieldList(&command->module)); - script_->commands.emplace_back(std::move(command)); + script->commands.emplace_back(std::move(command)); } else if (IsCommand(PeekPair())) { - CHECK_RESULT(ParseCommandList(&script_->commands)); + CHECK_RESULT(ParseCommandList(script.get(), &script->commands)); } else { ConsumeIfLpar(); ErrorExpected({"a module field", "a command"}); } EXPECT(Eof); - return errors_ == 0 ? Result::Ok : Result::Error; + if (errors_ == 0) { + *out_script = std::move(script); + return Result::Ok; + } else { + return Result::Error; + } } Result WastParser::ParseModuleFieldList(Module* module) { @@ -1660,11 +1693,12 @@ Result WastParser::ParseGlobalType(Global* global) { return Result::Ok; } -Result WastParser::ParseCommandList(CommandPtrVector* commands) { +Result WastParser::ParseCommandList(Script* script, + CommandPtrVector* commands) { WABT_TRACE(ParseCommandList); while (IsCommand(PeekPair())) { CommandPtr command; - if (Succeeded(ParseCommand(&command))) { + if (Succeeded(ParseCommand(script, &command))) { commands->push_back(std::move(command)); } else { CHECK_RESULT(Synchronize(IsCommand)); @@ -1673,7 +1707,7 @@ Result WastParser::ParseCommandList(CommandPtrVector* commands) { return Result::Ok; } -Result WastParser::ParseCommand(CommandPtr* out_command) { +Result WastParser::ParseCommand(Script* script, CommandPtr* out_command) { WABT_TRACE(ParseCommand); switch (Peek(1)) { case TokenType::AssertExhaustion: @@ -1705,7 +1739,7 @@ Result WastParser::ParseCommand(CommandPtr* out_command) { return ParseActionCommand(out_command); case TokenType::Module: - return ParseModuleCommand(out_command); + return ParseModuleCommand(script, out_command); case TokenType::Register: return ParseRegisterCommand(out_command); @@ -1793,7 +1827,7 @@ Result WastParser::ParseActionCommand(CommandPtr* out_command) { return Result::Ok; } -Result WastParser::ParseModuleCommand(CommandPtr* out_command) { +Result WastParser::ParseModuleCommand(Script* script, CommandPtr* out_command) { WABT_TRACE(ParseModuleCommand); std::unique_ptr<ScriptModule> script_module; CHECK_RESULT(ParseScriptModule(&script_module)); @@ -1822,14 +1856,18 @@ Result WastParser::ParseModuleCommand(CommandPtr* out_command) { return ErrorExpected({"a binary module", "a text module"}); } - Index command_index = script_->commands.size(); + // script is nullptr when ParseModuleCommand is called from ParseModule. + if (script) { + Index command_index = script->commands.size(); - if (!module.name.empty()) { - script_->module_bindings.emplace(module.name, - Binding(module.loc, command_index)); + if (!module.name.empty()) { + script->module_bindings.emplace(module.name, + Binding(module.loc, command_index)); + } + + last_module_index_ = command_index; } - last_module_index_ = command_index; *out_command = std::move(command); return Result::Ok; } @@ -1982,19 +2020,23 @@ void WastParser::CheckImportOrdering(Module* module) { } } -std::unique_ptr<Script> WastParser::ReleaseScript() { - return std::move(script_); +Result ParseWatModule(WastLexer* lexer, + std::unique_ptr<Module>* out_module, + ErrorHandler* error_handler, + WastParseOptions* options) { + assert(out_module != nullptr); + WastParser parser(lexer, error_handler, options); + return parser.ParseModule(out_module); } -Result ParseWast(WastLexer* lexer, - std::unique_ptr<Script>* out_script, - ErrorHandler* error_handler, - WastParseOptions* options) { + +Result ParseWastScript(WastLexer* lexer, + std::unique_ptr<Script>* out_script, + ErrorHandler* error_handler, + WastParseOptions* options) { assert(out_script != nullptr); WastParser parser(lexer, error_handler, options); - Result result = parser.ParseScript(); - *out_script = parser.ReleaseScript(); - return result; + return parser.ParseScript(out_script); } } // namespace wabt diff --git a/src/wast-parser.h b/src/wast-parser.h index 95f5bc96..c537c7f1 100644 --- a/src/wast-parser.h +++ b/src/wast-parser.h @@ -43,7 +43,9 @@ class WastParser { WastParser(WastLexer*, ErrorHandler*, WastParseOptions*); void WABT_PRINTF_FORMAT(3, 4) Error(Location, const char* format, ...); - Result ParseScript(); + Result ParseModule(std::unique_ptr<Module>* out_module); + Result ParseScript(std::unique_ptr<Script>* out_script); + std::unique_ptr<Script> ReleaseScript(); private: @@ -168,8 +170,8 @@ class WastParser { template <typename T> Result ParsePlainInstrVar(Location, std::unique_ptr<Expr>*); - Result ParseCommandList(CommandPtrVector*); - Result ParseCommand(CommandPtr*); + Result ParseCommandList(Script*, CommandPtrVector*); + Result ParseCommand(Script*, CommandPtr*); Result ParseAssertExhaustionCommand(CommandPtr*); Result ParseAssertInvalidCommand(CommandPtr*); Result ParseAssertMalformedCommand(CommandPtr*); @@ -179,7 +181,7 @@ class WastParser { Result ParseAssertTrapCommand(CommandPtr*); Result ParseAssertUnlinkableCommand(CommandPtr*); Result ParseActionCommand(CommandPtr*); - Result ParseModuleCommand(CommandPtr*); + Result ParseModuleCommand(Script*, CommandPtr*); Result ParseRegisterCommand(CommandPtr*); Result ParseAction(ActionPtr*); @@ -197,7 +199,6 @@ class WastParser { void CheckImportOrdering(Module*); WastLexer* lexer_; - std::unique_ptr<Script> script_; Index last_module_index_ = kInvalidIndex; ErrorHandler* error_handler_; int errors_ = 0; @@ -206,10 +207,15 @@ class WastParser { CircularArray<Token, 2> tokens_; }; -Result ParseWast(WastLexer* lexer, - std::unique_ptr<Script>* out_script, - ErrorHandler*, - WastParseOptions* options = nullptr); +Result ParseWatModule(WastLexer* lexer, + std::unique_ptr<Module>* out_module, + ErrorHandler*, + WastParseOptions* options = nullptr); + +Result ParseWastScript(WastLexer* lexer, + std::unique_ptr<Script>* out_script, + ErrorHandler*, + WastParseOptions* options = nullptr); } // namespace wabt diff --git a/test/parse/bad-crlf.txt b/test/parse/bad-crlf.txt index 207bfdce..ddf2676e 100644 --- a/test/parse/bad-crlf.txt +++ b/test/parse/bad-crlf.txt @@ -2,7 +2,7 @@ modulez
funcz
(;; STDERR ;;; -out/test/parse/bad-crlf.txt:2:1: error: unexpected token "modulez", expected a module field or a command. +out/test/parse/bad-crlf.txt:2:1: error: unexpected token "modulez", expected a module field or a module. modulez ^^^^^^^ out/test/parse/bad-crlf.txt:3:1: error: unexpected token funcz, expected EOF. diff --git a/test/parse/bad-error-long-line.txt b/test/parse/bad-error-long-line.txt index 451ac6fd..2f699c4e 100644 --- a/test/parse/bad-error-long-line.txt +++ b/test/parse/bad-error-long-line.txt @@ -1,7 +1,7 @@ ;;; ERROR: 1 whoops (; some text at the end of the line ;) (;; STDERR ;;; -out/test/parse/bad-error-long-line.txt:2:170: error: unexpected token "whoops", expected a module field or a command. +out/test/parse/bad-error-long-line.txt:2:170: error: unexpected token "whoops", expected a module field or a module. ... whoops (; some text... ^^^^^^ ;;; STDERR ;;) diff --git a/test/parse/bad-error-long-token.txt b/test/parse/bad-error-long-token.txt index 5236637d..ca5fbf0a 100644 --- a/test/parse/bad-error-long-token.txt +++ b/test/parse/bad-error-long-token.txt @@ -1,7 +1,7 @@ ;;; ERROR: 1 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz (;; STDERR ;;; -out/test/parse/bad-error-long-token.txt:2:15: error: unexpected token "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", expected a module field or a command. +out/test/parse/bad-error-long-token.txt:2:15: error: unexpected token "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", expected a module field or a module. abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;;; STDERR ;;) diff --git a/test/parse/bad-single-semicolon.txt b/test/parse/bad-single-semicolon.txt index 18ab20d8..fe67eea0 100644 --- a/test/parse/bad-single-semicolon.txt +++ b/test/parse/bad-single-semicolon.txt @@ -5,7 +5,7 @@ out/test/parse/bad-single-semicolon.txt:2:1: error: unexpected char ; foo bar ^ -out/test/parse/bad-single-semicolon.txt:2:3: error: unexpected token "foo", expected a module field or a command. +out/test/parse/bad-single-semicolon.txt:2:3: error: unexpected token "foo", expected a module field or a module. ; foo bar ^^^ out/test/parse/bad-single-semicolon.txt:2:7: error: unexpected token bar, expected EOF. diff --git a/test/parse/bad-toplevel.txt b/test/parse/bad-toplevel.txt index 9459b88e..ebf78714 100644 --- a/test/parse/bad-toplevel.txt +++ b/test/parse/bad-toplevel.txt @@ -1,7 +1,7 @@ ;;; ERROR: 1 (foo bar) (;; STDERR ;;; -out/test/parse/bad-toplevel.txt:2:2: error: unexpected token "foo", expected a module field or a command. +out/test/parse/bad-toplevel.txt:2:2: error: unexpected token "foo", expected a module field or a module. (foo bar) ^^^ out/test/parse/bad-toplevel.txt:2:6: error: unexpected token bar, expected EOF. diff --git a/test/parse/empty-file.txt b/test/parse/empty-file.txt index 0d021226..bdd75938 100644 --- a/test/parse/empty-file.txt +++ b/test/parse/empty-file.txt @@ -1,5 +1,5 @@ ;;; ERROR: 1 ;; empty file (;; STDERR ;;; -out/test/parse/empty-file.txt:3:2: error: unexpected token "EOF", expected a module field or a command. +out/test/parse/empty-file.txt:3:2: error: unexpected token "EOF", expected a module field or a module. ;;; STDERR ;;) diff --git a/test/parse/module/bad-module-multi.txt b/test/parse/module/bad-module-multi.txt new file mode 100644 index 00000000..10d8102a --- /dev/null +++ b/test/parse/module/bad-module-multi.txt @@ -0,0 +1,10 @@ +;;; ERROR: 1 +(module (func)) + +;; Can't have two modules in a .wat file. +(module) +(;; STDERR ;;; +out/test/parse/module/bad-module-multi.txt:5:1: error: unexpected token (, expected EOF. +(module) +^ +;;; STDERR ;;) diff --git a/test/parse/module/bad-module-with-assert.txt b/test/parse/module/bad-module-with-assert.txt new file mode 100644 index 00000000..5145f611 --- /dev/null +++ b/test/parse/module/bad-module-with-assert.txt @@ -0,0 +1,10 @@ +;;; ERROR: 1 +(module (func (export "f"))) + +;; Can't use assert_return when parsing a .wat file. +(assert_return (invoke "f")) +(;; STDERR ;;; +out/test/parse/module/bad-module-with-assert.txt:5:1: error: unexpected token (, expected EOF. +(assert_return (invoke "f")) +^ +;;; STDERR ;;) |