diff options
author | Heejin Ahn <aheejin@gmail.com> | 2021-12-29 21:44:07 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-29 21:44:07 -0800 |
commit | 6137b338c7fb37ba98b63c31225ec9cfda8cfa59 (patch) | |
tree | 5cf6f81fd9217e76160d486deb384dcbf77b0cf0 /src/tools/execution-results.h | |
parent | ad723a19b018a786bcbec8d9e16160f30959e60e (diff) | |
download | binaryen-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.h | 60 |
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. |