diff options
-rwxr-xr-x | auto_update_tests.py | 2 | ||||
-rwxr-xr-x | check.py | 2 | ||||
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 80 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 4 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input.wast | 63 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input.wast.ctors | 1 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input.wast.out | 17 | ||||
-rw-r--r-- | test/lit/help/wasm-ctor-eval.test | 3 |
8 files changed, 161 insertions, 11 deletions
diff --git a/auto_update_tests.py b/auto_update_tests.py index 76728f8a7..9f93142a8 100755 --- a/auto_update_tests.py +++ b/auto_update_tests.py @@ -87,6 +87,8 @@ def update_ctor_eval_tests(): print('..', os.path.basename(t)) ctors = open(t + '.ctors').read().strip() cmd = shared.WASM_CTOR_EVAL + [t, '-all', '-o', 'a.wast', '-S', '--ctors', ctors] + if 'ignore-external-input' in t: + cmd += ['--ignore-external-input'] support.run_command(cmd) actual = open('a.wast').read() out = t + '.out' @@ -116,6 +116,8 @@ def run_ctor_eval_tests(): print('..', os.path.basename(t)) ctors = open(t + '.ctors').read().strip() cmd = shared.WASM_CTOR_EVAL + [t, '-all', '-o', 'a.wat', '-S', '--ctors', ctors] + if 'ignore-external-input' in t: + cmd += ['--ignore-external-input'] support.run_command(cmd) actual = open('a.wat').read() out = t + '.out' diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index b0a1c0551..009a91c0b 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -142,7 +142,7 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) { // create empty functions with similar signature ModuleUtils::iterImportedFunctions(wasm, [&](Function* func) { - if (func->module == "env") { + if (func->module == env->name) { Builder builder(*env); auto* copied = ModuleUtils::copyFunction(func, *env); copied->module = Name(); @@ -155,7 +155,7 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) { // create tables with similar initial and max values ModuleUtils::iterImportedTables(wasm, [&](Table* table) { - if (table->module == "env") { + if (table->module == env->name) { auto* copied = ModuleUtils::copyTable(table, *env); copied->module = Name(); copied->base = Name(); @@ -165,7 +165,7 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) { }); ModuleUtils::iterImportedGlobals(wasm, [&](Global* global) { - if (global->module == "env") { + if (global->module == env->name) { auto* copied = ModuleUtils::copyGlobal(global, *env); copied->module = Name(); copied->base = Name(); @@ -179,7 +179,7 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) { // create an exported memory with the same initial and max size ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) { - if (memory->module == "env") { + if (memory->module == env->name) { env->memory.name = wasm.memory.name; env->memory.exists = true; env->memory.initial = memory->initial; @@ -194,6 +194,11 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) { return env; } +// Whether to ignore external input to the program as it runs. If set, we will +// assume that stdin is empty, that any env vars we try to read are not set, +// that there are not arguments passed to main, etc. +static bool ignoreExternalInput = false; + struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface { Module* wasm; EvallingModuleInstance* instance; @@ -242,10 +247,63 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface { } Literals callImport(Function* import, LiteralList& arguments) override { + Name WASI("wasi_snapshot_preview1"); + + if (ignoreExternalInput) { + if (import->module == WASI) { + if (import->base == "environ_sizes_get") { + if (arguments.size() != 2 || arguments[0].type != Type::i32 || + import->getResults() != Type::i32) { + throw FailToEvalException("wasi environ_sizes_get has wrong sig"); + } + + // Write out a count of i32(0) and return __WASI_ERRNO_SUCCESS (0). + store32(arguments[0].geti32(), 0); + return {Literal(int32_t(0))}; + } + + if (import->base == "environ_get") { + if (arguments.size() != 2 || arguments[0].type != Type::i32 || + import->getResults() != Type::i32) { + throw FailToEvalException("wasi environ_get has wrong sig"); + } + + // Just return __WASI_ERRNO_SUCCESS (0). + return {Literal(int32_t(0))}; + } + + if (import->base == "args_sizes_get") { + if (arguments.size() != 2 || arguments[0].type != Type::i32 || + import->getResults() != Type::i32) { + throw FailToEvalException("wasi args_sizes_get has wrong sig"); + } + + // Write out an argc of i32(0) and return a __WASI_ERRNO_SUCCESS (0). + store32(arguments[0].geti32(), 0); + return {Literal(int32_t(0))}; + } + + if (import->base == "args_get") { + if (arguments.size() != 2 || arguments[0].type != Type::i32 || + import->getResults() != Type::i32) { + throw FailToEvalException("wasi args_get has wrong sig"); + } + + // Just return __WASI_ERRNO_SUCCESS (0). + return {Literal(int32_t(0))}; + } + + // Otherwise, we don't recognize this import; continue normally to + // error. + } + } + std::string extra; if (import->module == ENV && import->base == "___cxa_atexit") { extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls " "to atexit are not emitted"; + } else if (import->module == WASI && !ignoreExternalInput) { + extra = "\nrecommendation: consider --ignore-external-input"; } throw FailToEvalException(std::string("call import: ") + import->module.str + "." + import->base.str + @@ -416,14 +474,14 @@ private: }; void evalCtors(Module& wasm, std::vector<std::string> ctors) { + std::map<Name, std::shared_ptr<EvallingModuleInstance>> linkedInstances; + // build and link the env module auto envModule = buildEnvModule(wasm); CtorEvalExternalInterface envInterface; auto envInstance = std::make_shared<EvallingModuleInstance>(*envModule, &envInterface); - - std::map<Name, std::shared_ptr<EvallingModuleInstance>> linkedInstances; - linkedInstances["env"] = envInstance; + linkedInstances[envModule->name] = envInstance; CtorEvalExternalInterface interface(linkedInstances); try { @@ -525,6 +583,14 @@ int main(int argc, const char* argv[]) { WasmCtorEvalOption, Options::Arguments::One, [&](Options* o, const std::string& argument) { ctorsString = argument; }) + .add("--ignore-external-input", + "-ipi", + "Assumes no env vars are to be read, stdin is empty, etc.", + WasmCtorEvalOption, + Options::Arguments::Zero, + [&](Options* o, const std::string& argument) { + ignoreExternalInput = true; + }) .add_positional("INFILE", Options::Arguments::One, [](Options* o, const std::string& argument) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index ecfc00d93..600310c9c 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -35,10 +35,6 @@ #include "wasm-traversal.h" #include "wasm.h" -#ifdef WASM_INTERPRETER_DEBUG -#include "wasm-printing.h" -#endif - namespace wasm { struct WasmException { diff --git a/test/ctor-eval/ignore-external-input.wast b/test/ctor-eval/ignore-external-input.wast new file mode 100644 index 000000000..0849c67ab --- /dev/null +++ b/test/ctor-eval/ignore-external-input.wast @@ -0,0 +1,63 @@ +(module + (import "wasi_snapshot_preview1" "environ_sizes_get" (func $wasi_environ_sizes_get (param i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "environ_get" (func $wasi_environ_get (param i32 i32) (result i32))) + + (import "wasi_snapshot_preview1" "args_sizes_get" (func $wasi_args_sizes_get (param i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "args_get" (func $wasi_args_get (param i32 i32) (result i32))) + + (import "wasi_snapshot_preview1" "something_else" (func $wasi_something_else (result i32))) + + (memory 256 256) + (data (i32.const 0) "aaaaaaaaaaaaaaaaaaaaaaaaaaaa") ;; the final 4 'a's will remain + + (func "test1" + ;; This is ok to call: when ignoring external input we assume there is no + ;; environment to read. + (i32.store + (i32.const 0) ;; the result (0) will be written to address 0 + (call $wasi_environ_sizes_get + (i32.const 4) ;; count (0) will be written to address 4 + (i32.const 0) + ) + ) + (i32.store + (i32.const 8) ;; the result (0) will be written to address 8 + (call $wasi_environ_get + (i32.const 0) + (i32.const 0) + ) + ) + ) + + (func "test2" + ;; This is also ok to call: when ignoring external input we assume there are + ;; not args passed to main. + (i32.store + (i32.const 12) ;; the result (0) will be written to address 12 + (call $wasi_args_sizes_get + (i32.const 16) ;; argc (0) will be written to address 16 + (i32.const 0) + ) + ) + (i32.store + (i32.const 20) ;; the result (0) will be written to address 20 + (call $wasi_args_get + (i32.const 0) + (i32.const 0) + ) + ) + ) + + (func "test3" + ;; This is *not* ok to call, and we will *not* reach the final store after + ;; this call. This function will not be evalled and will remain in the + ;; output. + (drop + (call $wasi_something_else) + ) + (i32.store + (i32.const 24) + (i32.const 100) + ) + ) +) diff --git a/test/ctor-eval/ignore-external-input.wast.ctors b/test/ctor-eval/ignore-external-input.wast.ctors new file mode 100644 index 000000000..c7060ede5 --- /dev/null +++ b/test/ctor-eval/ignore-external-input.wast.ctors @@ -0,0 +1 @@ +test1,test2,test3 diff --git a/test/ctor-eval/ignore-external-input.wast.out b/test/ctor-eval/ignore-external-input.wast.out new file mode 100644 index 000000000..f728afd0e --- /dev/null +++ b/test/ctor-eval/ignore-external-input.wast.out @@ -0,0 +1,17 @@ +(module + (type $none_=>_i32 (func (result i32))) + (type $none_=>_none (func)) + (import "wasi_snapshot_preview1" "something_else" (func $wasi_something_else (result i32))) + (memory $0 256 256) + (data (i32.const 24) "aaaa") + (export "test3" (func $2)) + (func $2 + (drop + (call $wasi_something_else) + ) + (i32.store + (i32.const 24) + (i32.const 100) + ) + ) +) diff --git a/test/lit/help/wasm-ctor-eval.test b/test/lit/help/wasm-ctor-eval.test index cf0671c81..364ac5d4c 100644 --- a/test/lit/help/wasm-ctor-eval.test +++ b/test/lit/help/wasm-ctor-eval.test @@ -19,6 +19,9 @@ ;; CHECK-NEXT: --ctors,-c Comma-separated list of global ;; CHECK-NEXT: constructor functions to evaluate ;; CHECK-NEXT: +;; CHECK-NEXT: --ignore-external-input,-ipi Assumes no env vars are to be read, stdin +;; CHECK-NEXT: is empty, etc. +;; CHECK-NEXT: ;; CHECK-NEXT: ;; CHECK-NEXT: Tool options: ;; CHECK-NEXT: ------------- |