summaryrefslogtreecommitdiff
path: root/src/tools/wasm-ctor-eval.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-01-06 15:04:42 -0800
committerGitHub <noreply@github.com>2022-01-06 15:04:42 -0800
commit8c0f53d236f664086405870321e5887aaed39f3f (patch)
treee2d8153967535df252db9c98af584841cf7c5a38 /src/tools/wasm-ctor-eval.cpp
parent5049f077ae2d21166dc8ee4c3057bdc48cb3d94c (diff)
downloadbinaryen-8c0f53d236f664086405870321e5887aaed39f3f.tar.gz
binaryen-8c0f53d236f664086405870321e5887aaed39f3f.tar.bz2
binaryen-8c0f53d236f664086405870321e5887aaed39f3f.zip
[ctor-eval] Add --ignore-external-input option (#4428)
This is meant to address one of the main limitations of wasm-ctor-eval in emscripten atm, that libc++ global ctors will read env vars, which means they call an import, which stops us from evalling, emscripten-core/emscripten#15403 (comment) To handle that, this adds an option to ignore external input. When set, we can assume that no env vars will be read, no reading from stdin, no arguments to main(), etc. Perhaps these could each be separate options, but I think keeping it simple for now might be good enough.
Diffstat (limited to 'src/tools/wasm-ctor-eval.cpp')
-rw-r--r--src/tools/wasm-ctor-eval.cpp80
1 files changed, 73 insertions, 7 deletions
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) {