diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 7173ec0fb64..b33fb5aa999 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -115,79 +115,63 @@ class EvallingModuleRunner : public ModuleRunnerBase { } }; -// Build artificial modules based on a module's imports, so that the +// Build an artificial `env` module based on a module's imports, so that the // interpreter can use correct object instances. It initializes usable global // imports, and fills the rest with fake values since those are dangerous to -// use. Imported globals can't be read anyway; see -// `EvallingModuleRunner::visitGlobalGet`. -// Note: wasi_ modules have stubs generated but won't be called due to the -// special handling in `CtorEvalExternalInterface::getImportedFunction`. We -// still generate the stubs to ensure the link-time validation passes. -std::vector> buildStubModules(Module& wasm) { - std::map> modules; - - ModuleUtils::iterImports( - wasm, - [&modules](std::variant import) { - Importable* importable = - std::visit([](auto* i) -> Importable* { return i; }, import); - - auto [it, inserted] = modules.try_emplace(importable->module, nullptr); - if (inserted) { - it->second = std::make_unique(); - it->second->name = importable->module; - } - Module* module = it->second.get(); - - struct Visitor { - Module* module; - void operator()(Memory* memory) { - auto* copied = ModuleUtils::copyMemory(memory, *module); - copied->module = Name(); - copied->base = Name(); - module->addExport(Builder(*module).makeExport( - memory->base, copied->name, ExternalKind::Memory)); - } - void operator()(Table* table) { - // create tables with similar initial and max values - auto* copied = ModuleUtils::copyTable(table, *module); - copied->module = Name(); - copied->base = Name(); - module->addExport(Builder(*module).makeExport( - table->base, copied->name, ExternalKind::Table)); - } - void operator()(Global* global) { - auto* copied = ModuleUtils::copyGlobal(global, *module); - copied->module = Name(); - copied->base = Name(); - - Builder builder(*module); - copied->init = builder.makeConst(Literal::makeZero(global->type)); - module->addExport(builder.makeExport( - global->base, copied->name, ExternalKind::Global)); - } - void operator()(Function* func) { - Builder builder(*module); - auto* copied = ModuleUtils::copyFunction(func, *module); - copied->module = Name(); - copied->base = Name(); - copied->body = builder.makeUnreachable(); - module->addExport(builder.makeExport( - func->base, copied->name, ExternalKind::Function)); - } - void operator()(Tag* tag) { - // no-op - } - }; - std::visit(Visitor{module}, import); - }); +// use. we will fail if dangerous globals are used. +std::unique_ptr buildEnvModule(Module& wasm) { + auto env = std::make_unique(); + env->name = "env"; + + // create empty functions with similar signature + ModuleUtils::iterImportedFunctions(wasm, [&](Function* func) { + if (func->module == env->name) { + Builder builder(*env); + auto* copied = ModuleUtils::copyFunction(func, *env); + copied->module = Name(); + copied->base = Name(); + copied->body = builder.makeUnreachable(); + env->addExport( + builder.makeExport(func->base, copied->name, ExternalKind::Function)); + } + }); + + // create tables with similar initial and max values + ModuleUtils::iterImportedTables(wasm, [&](Table* table) { + if (table->module == env->name) { + auto* copied = ModuleUtils::copyTable(table, *env); + copied->module = Name(); + copied->base = Name(); + env->addExport(Builder(*env).makeExport( + table->base, copied->name, ExternalKind::Table)); + } + }); + + ModuleUtils::iterImportedGlobals(wasm, [&](Global* global) { + if (global->module == env->name) { + auto* copied = ModuleUtils::copyGlobal(global, *env); + copied->module = Name(); + copied->base = Name(); + + Builder builder(*env); + copied->init = builder.makeConst(Literal::makeZero(global->type)); + env->addExport( + builder.makeExport(global->base, copied->name, ExternalKind::Global)); + } + }); + + // create an exported memory with the same initial and max size + ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) { + if (memory->module == env->name) { + auto* copied = ModuleUtils::copyMemory(memory, *env); + copied->module = Name(); + copied->base = Name(); + env->addExport(Builder(*env).makeExport( + memory->base, copied->name, ExternalKind::Memory)); + } + }); - std::vector> modulesVector; - modulesVector.reserve(modules.size()); - for (auto& [_, ptr] : modules) { - modulesVector.push_back(std::move(ptr)); - } - return modulesVector; + return env; } // Whether to ignore external input to the program as it runs. If set, we will @@ -1372,16 +1356,12 @@ void evalCtors(Module& wasm, std::map> linkedInstances; - // stubModules and interfaces must be kept alive since they are referenced in - // linkedInstances. - std::vector> stubModules = buildStubModules(wasm); - std::vector> interfaces; - - for (auto& module : stubModules) { - interfaces.push_back(std::make_unique()); - linkedInstances[module->name] = - std::make_shared(*module, interfaces.back().get()); - } + // build and link the env module + auto envModule = buildEnvModule(wasm); + CtorEvalExternalInterface envInterface; + auto envInstance = + std::make_shared(*envModule, &envInterface); + linkedInstances[envModule->name] = envInstance; CtorEvalExternalInterface interface(linkedInstances); try { diff --git a/test/ctor-eval/global-get-init.wast b/test/ctor-eval/global-get-init.wast index 5c085e245cb..125e672d6c5 100644 --- a/test/ctor-eval/global-get-init.wast +++ b/test/ctor-eval/global-get-init.wast @@ -1,9 +1,8 @@ (module (import "import" "global" (global $imported i32)) - (func $use-global (export "use-global") (result i32) - (global.get $imported) + (func $test1 (export "test1") + ;; This should be safe to eval in theory, but the imported global stops us, + ;; so this function will not be optimized out. + ;; TODO: perhaps if we never use that global that is ok? ) - ;; The imported global isn't used in the ctor, - ;; so we're free to remove it completely. - (func $test1 (export "test1")) ) diff --git a/test/ctor-eval/global-get-init.wast.out b/test/ctor-eval/global-get-init.wast.out index 0e5138fb621..519e96dbabd 100644 --- a/test/ctor-eval/global-get-init.wast.out +++ b/test/ctor-eval/global-get-init.wast.out @@ -1,8 +1,7 @@ (module - (type $0 (func (result i32))) - (import "import" "global" (global $imported i32)) - (export "use-global" (func $use-global)) - (func $use-global (type $0) (result i32) - (global.get $imported) + (type $0 (func)) + (export "test1" (func $test1)) + (func $test1 (type $0) + (nop) ) )