summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2021-12-06 17:12:07 -0800
committerGitHub <noreply@github.com>2021-12-06 17:12:07 -0800
commitf0d835165aea108b213a2b9ea148453a917223d5 (patch)
tree8f695d97d3d8a46c4ff0cf308b8a90f4030fd218 /src
parentf0668172831da496a6a781c82fa4b2dc0f4c9028 (diff)
downloadbinaryen-f0d835165aea108b213a2b9ea148453a917223d5.tar.gz
binaryen-f0d835165aea108b213a2b9ea148453a917223d5.tar.bz2
binaryen-f0d835165aea108b213a2b9ea148453a917223d5.zip
[EH] Make interpreter handle uncaught exceptions (#4369)
When a wasm exception is thrown and uncaught in the interpreter, it caused the whole interpreter to crash, rather than gracefully reporting it. This fixes the problem, and also compares whether an uncaught exception happened when comparing the results before and after optimizations in `--fuzz-exec`. To do that, when `--fuzz-exec` is given, we now compare results even when the function does not have return values. Logs for some existing test have changed because of this.
Diffstat (limited to 'src')
-rw-r--r--src/tools/execution-results.h52
1 files changed, 28 insertions, 24 deletions
diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h
index b689ffc66..18f4a399c 100644
--- a/src/tools/execution-results.h
+++ b/src/tools/execution-results.h
@@ -87,7 +87,11 @@ 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 {
- std::map<Name, Literals> results;
+ struct FunctionResult {
+ Literals values;
+ bool exception; // Whether an exception is uncaught and the function crashes
+ };
+ std::map<Name, FunctionResult> results;
Loggings loggings;
// If set, we should ignore this and not compare it to anything.
@@ -106,26 +110,20 @@ struct ExecutionResults {
}
std::cout << "[fuzz-exec] calling " << exp->name << "\n";
auto* func = wasm.getFunction(exp->value);
- if (func->getResults() != Type::none) {
- // this has a result
- Literals ret = run(func, wasm, instance);
- results[exp->name] = ret;
- // ignore the result if we hit an unreachable and returned no value
- if (ret.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 << '\n';
- }
+ 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';
}
- } else {
- // no result, run it anyhow (it might modify memory etc.)
- run(func, wasm, instance);
}
}
} catch (const TrapException&) {
@@ -191,7 +189,10 @@ struct ExecutionResults {
return false;
}
std::cout << "[fuzz-exec] comparing " << name << '\n';
- if (!areEqual(results[name], other.results[name])) {
+ if (!areEqual(results[name].values, other.results[name].values)) {
+ return false;
+ }
+ if (results[name].exception != other.results[name].exception) {
return false;
}
}
@@ -209,7 +210,7 @@ struct ExecutionResults {
bool operator!=(ExecutionResults& other) { return !((*this) == other); }
- Literals run(Function* func, Module& wasm) {
+ FunctionResult run(Function* func, Module& wasm) {
LoggingExternalInterface interface(loggings);
try {
ModuleInstance instance(wasm, &interface);
@@ -220,7 +221,7 @@ struct ExecutionResults {
}
}
- Literals run(Function* func, Module& wasm, ModuleInstance& instance) {
+ FunctionResult run(Function* func, Module& wasm, ModuleInstance& instance) {
try {
LiteralList arguments;
// init hang support, if present
@@ -236,9 +237,12 @@ struct ExecutionResults {
}
arguments.push_back(Literal::makeZero(param));
}
- return instance.callFunction(func->name, arguments);
+ return {instance.callFunction(func->name, arguments), false};
} catch (const TrapException&) {
return {};
+ } catch (const WasmException& e) {
+ std::cout << "[exception thrown: " << e << "]" << std::endl;
+ return {{}, true};
} catch (const HostLimitException&) {
// This should be ignored and not compared with, as optimizations can
// change whether a host limit is reached.