summaryrefslogtreecommitdiff
path: root/src/tools/execution-results.h
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2021-12-29 21:44:07 -0800
committerGitHub <noreply@github.com>2021-12-29 21:44:07 -0800
commit6137b338c7fb37ba98b63c31225ec9cfda8cfa59 (patch)
tree5cf6f81fd9217e76160d486deb384dcbf77b0cf0 /src/tools/execution-results.h
parentad723a19b018a786bcbec8d9e16160f30959e60e (diff)
downloadbinaryen-6137b338c7fb37ba98b63c31225ec9cfda8cfa59.tar.gz
binaryen-6137b338c7fb37ba98b63c31225ec9cfda8cfa59.tar.bz2
binaryen-6137b338c7fb37ba98b63c31225ec9cfda8cfa59.zip
Compare traps in ExecutionResults (#4405)
We used to only compare return values, and in #4369 we started comparing whether an uncaught exception was thrown. This also adds whether a trap occurred to `ExecutionResults`. So in `--fuzz-exec`, if a program with a trap loses the trap or vice versa, it will error out saying the result has changed, unless either of `--ignore-implicit-traps` or `--trans-never-happen` is set.
Diffstat (limited to 'src/tools/execution-results.h')
-rw-r--r--src/tools/execution-results.h60
1 files changed, 38 insertions, 22 deletions
diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h
index 18f4a399c..afd7a78c1 100644
--- a/src/tools/execution-results.h
+++ b/src/tools/execution-results.h
@@ -87,15 +87,20 @@ struct LoggingExternalInterface : public ShellExternalInterface {
// we can only get results when there are no imports. we then call each method
// that has a result, with some values
struct ExecutionResults {
- struct FunctionResult {
- Literals values;
- bool exception; // Whether an exception is uncaught and the function crashes
- };
+ struct Trap {};
+ struct Exception {};
+ using FunctionResult = std::variant<Literals, Trap, Exception>;
std::map<Name, FunctionResult> results;
Loggings loggings;
// If set, we should ignore this and not compare it to anything.
bool ignore = false;
+ // If set, we don't compare whether a trap has occurred or not.
+ bool ignoreTrap = false;
+
+ ExecutionResults(const PassOptions& options)
+ : ignoreTrap(options.ignoreImplicitTraps || options.trapsNeverHappen) {}
+ ExecutionResults(bool ignoreTrap) : ignoreTrap(ignoreTrap) {}
// get results of execution
void get(Module& wasm) {
@@ -112,17 +117,19 @@ struct ExecutionResults {
auto* func = wasm.getFunction(exp->value);
FunctionResult ret = run(func, wasm, instance);
results[exp->name] = ret;
- // ignore the result if we hit an unreachable and returned no value
- if (ret.values.size() > 0) {
- std::cout << "[fuzz-exec] note result: " << exp->name << " => ";
- auto resultType = func->getResults();
- if (resultType.isRef()) {
- // Don't print reference values, as funcref(N) contains an index
- // for example, which is not guaranteed to remain identical after
- // optimizations.
- std::cout << resultType << '\n';
- } else {
- std::cout << ret.values << '\n';
+ if (auto* values = std::get_if<Literals>(&ret)) {
+ // ignore the result if we hit an unreachable and returned no value
+ if (values->size() > 0) {
+ std::cout << "[fuzz-exec] note result: " << exp->name << " => ";
+ auto resultType = func->getResults();
+ if (resultType.isRef()) {
+ // Don't print reference values, as funcref(N) contains an index
+ // for example, which is not guaranteed to remain identical after
+ // optimizations.
+ std::cout << resultType << '\n';
+ } else {
+ std::cout << *values << '\n';
+ }
}
}
}
@@ -133,7 +140,7 @@ struct ExecutionResults {
// get current results and check them against previous ones
void check(Module& wasm) {
- ExecutionResults optimizedResults;
+ ExecutionResults optimizedResults(ignoreTrap);
optimizedResults.get(wasm);
if (optimizedResults != *this) {
std::cout << "[fuzz-exec] optimization passes changed results\n";
@@ -189,10 +196,19 @@ struct ExecutionResults {
return false;
}
std::cout << "[fuzz-exec] comparing " << name << '\n';
- if (!areEqual(results[name].values, other.results[name].values)) {
- return false;
+ if (results[name].index() != other.results[name].index()) {
+ if (ignoreTrap) {
+ if (!std::get_if<Trap>(&results[name]) &&
+ !std::get_if<Trap>(&other.results[name])) {
+ return false;
+ }
+ } else {
+ return false;
+ }
}
- if (results[name].exception != other.results[name].exception) {
+ auto* values = std::get_if<Literals>(&results[name]);
+ auto* otherValues = std::get_if<Literals>(&other.results[name]);
+ if (values && otherValues && !areEqual(*values, *otherValues)) {
return false;
}
}
@@ -237,12 +253,12 @@ struct ExecutionResults {
}
arguments.push_back(Literal::makeZero(param));
}
- return {instance.callFunction(func->name, arguments), false};
+ return instance.callFunction(func->name, arguments);
} catch (const TrapException&) {
- return {};
+ return Trap{};
} catch (const WasmException& e) {
std::cout << "[exception thrown: " << e << "]" << std::endl;
- return {{}, true};
+ return Exception{};
} catch (const HostLimitException&) {
// This should be ignored and not compared with, as optimizations can
// change whether a host limit is reached.