summaryrefslogtreecommitdiff
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
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.
-rw-r--r--src/tools/execution-results.h52
-rw-r--r--test/lit/exec/eh.wast64
-rw-r--r--test/passes/fuzz-exec_all-features.txt4
-rw-r--r--test/passes/optimize-instructions_fuzz-exec.txt6
4 files changed, 102 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.
diff --git a/test/lit/exec/eh.wast b/test/lit/exec/eh.wast
new file mode 100644
index 000000000..779309eb6
--- /dev/null
+++ b/test/lit/exec/eh.wast
@@ -0,0 +1,64 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --output=fuzz-exec and should not be edited.
+
+;; RUN: wasm-opt %s -all --fuzz-exec -q -o /dev/null 2>&1 | filecheck %s
+
+(module
+ (tag $e-i32 (param i32))
+
+ ;; CHECK: [fuzz-exec] calling throw
+ ;; CHECK-NEXT: [exception thrown: e-i32 1]
+ (func "throw"
+ (throw $e-i32 (i32.const 1))
+ )
+
+ ;; CHECK: [fuzz-exec] calling try-catch
+ (func "try-catch"
+ (try
+ (do
+ (throw $e-i32 (i32.const 2))
+ )
+ (catch $e-i32
+ (drop (pop i32))
+ )
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling catchless-try
+ ;; CHECK-NEXT: [exception thrown: e-i32 3]
+ (func "catchless-try"
+ (try
+ (do
+ (throw $e-i32 (i32.const 3))
+ )
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling try-delegate
+ ;; CHECK-NEXT: [exception thrown: e-i32 4]
+ (func "try-delegate"
+ (try $l0
+ (do
+ (try
+ (do
+ (throw $e-i32 (i32.const 4))
+ )
+ (delegate $l0)
+ )
+ )
+ )
+ )
+)
+;; CHECK: [fuzz-exec] calling throw
+;; CHECK-NEXT: [exception thrown: e-i32 1]
+
+;; CHECK: [fuzz-exec] calling try-catch
+
+;; CHECK: [fuzz-exec] calling catchless-try
+;; CHECK-NEXT: [exception thrown: e-i32 3]
+
+;; CHECK: [fuzz-exec] calling try-delegate
+;; CHECK-NEXT: [exception thrown: e-i32 4]
+;; CHECK-NEXT: [fuzz-exec] comparing catchless-try
+;; CHECK-NEXT: [fuzz-exec] comparing throw
+;; CHECK-NEXT: [fuzz-exec] comparing try-catch
+;; CHECK-NEXT: [fuzz-exec] comparing try-delegate
diff --git a/test/passes/fuzz-exec_all-features.txt b/test/passes/fuzz-exec_all-features.txt
index 0225876a1..4b3e64e7c 100644
--- a/test/passes/fuzz-exec_all-features.txt
+++ b/test/passes/fuzz-exec_all-features.txt
@@ -139,9 +139,11 @@
[fuzz-exec] calling oob_notify
[trap final > memory: 18446744073709551512 > 65514]
[fuzz-exec] comparing aligned_for_size
+[fuzz-exec] comparing oob_notify
[fuzz-exec] comparing unaligned_load
[fuzz-exec] comparing unaligned_load_offset
[fuzz-exec] comparing unaligned_notify
+[fuzz-exec] comparing wrap_cmpxchg
[fuzz-exec] calling unsigned_2_bytes
[fuzz-exec] note result: unsigned_2_bytes => 65535
(module
@@ -183,6 +185,7 @@
)
[fuzz-exec] calling rmw-reads-modifies-and-writes
[LoggingExternalInterface logging 0]
+[fuzz-exec] comparing rmw-reads-modifies-and-writes
[fuzz-exec] calling rmw-reads-modifies-and-writes-asymmetrical
[LoggingExternalInterface logging 214]
(module
@@ -207,6 +210,7 @@
)
[fuzz-exec] calling rmw-reads-modifies-and-writes-asymmetrical
[LoggingExternalInterface logging 214]
+[fuzz-exec] comparing rmw-reads-modifies-and-writes-asymmetrical
[fuzz-exec] calling func
[fuzz-exec] note result: func => funcref
(module
diff --git a/test/passes/optimize-instructions_fuzz-exec.txt b/test/passes/optimize-instructions_fuzz-exec.txt
index 2ebd01f1c..ea32b8916 100644
--- a/test/passes/optimize-instructions_fuzz-exec.txt
+++ b/test/passes/optimize-instructions_fuzz-exec.txt
@@ -253,6 +253,10 @@
[LoggingExternalInterface logging nan:0x400000]
[LoggingExternalInterface logging nan:0x400000]
[LoggingExternalInterface logging nan:0x400000]
+[fuzz-exec] comparing ignore
+[fuzz-exec] comparing just-one-nan
+[fuzz-exec] comparing test32
+[fuzz-exec] comparing test64
[fuzz-exec] calling foo
[LoggingExternalInterface logging 1]
[LoggingExternalInterface logging 1]
@@ -381,3 +385,5 @@
[fuzz-exec] note result: call-compare-maybe-signed-ne => 1
[fuzz-exec] comparing call-compare-maybe-signed-eq
[fuzz-exec] comparing call-compare-maybe-signed-ne
+[fuzz-exec] comparing do-shift
+[fuzz-exec] comparing foo