summaryrefslogtreecommitdiff
path: root/src/tools/wasm-ctor-eval.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-01-11 13:29:10 -0800
committerGitHub <noreply@github.com>2022-01-11 13:29:10 -0800
commitcc36ffd13f6794cc5212a1f0ba7f58e816e8a0de (patch)
tree48557d4f56f512d2a07f82c4b27a28f052d2eff7 /src/tools/wasm-ctor-eval.cpp
parent1e7e248d890d27a40f3dc287bd82834930f81e5c (diff)
downloadbinaryen-cc36ffd13f6794cc5212a1f0ba7f58e816e8a0de.tar.gz
binaryen-cc36ffd13f6794cc5212a1f0ba7f58e816e8a0de.tar.bz2
binaryen-cc36ffd13f6794cc5212a1f0ba7f58e816e8a0de.zip
[ctor-eval] Add an option to keep some exports (#4441)
By default wasm-ctor-eval removes exports that it manages to completely eval (if it just partially evals then the export remains, but points to a function with partially-evalled contents). However, in some cases we do want to keep the export around even so, for example during fuzzing (as the fuzzer wants to call the same exports before and after wasm-ctor-eval runs) and also if there is an ABI we need to preserve (like if we manage to eval all of main()), or if the function returns a value (which we don't support yet, but this is a PR to prepare for that). Specifically, there is now a new option: --kept-exports foo,bar That is a list of exports to keep around. Note that when we keep around an export after evalling the ctor we make the export point to a new function. That new function just contains a nop, so that nothing happens when it is called. But the original function is kept around as it may have other callers, who we do not want to modify.
Diffstat (limited to 'src/tools/wasm-ctor-eval.cpp')
-rw-r--r--src/tools/wasm-ctor-eval.cpp54
1 files changed, 39 insertions, 15 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index 867335a20..e6883e351 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -33,6 +33,7 @@
#include "pass.h"
#include "support/colors.h"
#include "support/file.h"
+#include "support/string.h"
#include "tool-options.h"
#include "wasm-builder.h"
#include "wasm-interpreter.h"
@@ -645,7 +646,12 @@ bool evalCtor(EvallingModuleInstance& instance,
}
// Eval all ctors in a module.
-void evalCtors(Module& wasm, std::vector<std::string> ctors) {
+void evalCtors(Module& wasm,
+ std::vector<std::string>& ctors,
+ std::vector<std::string>& keptExports) {
+ std::unordered_set<std::string> keptExportsSet(keptExports.begin(),
+ keptExports.end());
+
std::map<Name, std::shared_ptr<EvallingModuleInstance>> linkedInstances;
// build and link the env module
@@ -683,7 +689,20 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
// Success! Remove the export, and continue.
std::cout << " ...success on " << ctor << ".\n";
- wasm.removeExport(ctor);
+
+ // Remove the export if we should.
+ auto* exp = wasm.getExport(ctor);
+ if (!keptExportsSet.count(ctor)) {
+ wasm.removeExport(exp->name);
+ } else {
+ // We are keeping around the export, which should now refer to an
+ // empty function since calling the export should do nothing.
+ auto* func = wasm.getFunction(exp->value);
+ auto copyName = Names::getValidFunctionName(wasm, func->name);
+ auto* copyFunc = ModuleUtils::copyFunction(func, wasm, copyName);
+ copyFunc->body = Builder(wasm).makeNop();
+ wasm.getExport(exp->name)->value = copyName;
+ }
}
} catch (FailToEvalException& fail) {
// that's it, we failed to even create the instance
@@ -704,7 +723,8 @@ int main(int argc, const char* argv[]) {
std::vector<std::string> passes;
bool emitBinary = true;
bool debugInfo = false;
- std::string ctorsString;
+ String::Split ctors;
+ String::Split keptExports;
const std::string WasmCtorEvalOption = "wasm-ctor-eval options";
@@ -732,13 +752,24 @@ int main(int argc, const char* argv[]) {
WasmCtorEvalOption,
Options::Arguments::Zero,
[&](Options* o, const std::string& arguments) { debugInfo = true; })
+ .add("--ctors",
+ "-c",
+ "Comma-separated list of global constructor functions to evaluate",
+ WasmCtorEvalOption,
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) {
+ ctors = String::Split(argument, ",");
+ })
.add(
- "--ctors",
- "-c",
- "Comma-separated list of global constructor functions to evaluate",
+ "--kept-exports",
+ "-ke",
+ "Comma-separated list of ctors whose exports we keep around even if we "
+ "eval those ctors",
WasmCtorEvalOption,
Options::Arguments::One,
- [&](Options* o, const std::string& argument) { ctorsString = argument; })
+ [&](Options* o, const std::string& argument) {
+ keptExports = String::Split(argument, ",");
+ })
.add("--ignore-external-input",
"-ipi",
"Assumes no env vars are to be read, stdin is empty, etc.",
@@ -777,14 +808,7 @@ int main(int argc, const char* argv[]) {
Fatal() << "error in validating input";
}
- // get list of ctors, and eval them
- std::vector<std::string> ctors;
- std::istringstream stream(ctorsString);
- std::string temp;
- while (std::getline(stream, temp, ',')) {
- ctors.push_back(temp);
- }
- evalCtors(wasm, ctors);
+ evalCtors(wasm, ctors, keptExports);
// Do some useful optimizations after the evalling
{