diff options
author | Alon Zakai <azakai@google.com> | 2021-04-12 18:37:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-12 18:37:48 -0700 |
commit | b0af95200a37d76eccf285dcb45b4ed6162212d0 (patch) | |
tree | 3633c42ad4935b06f2fe88a8e9901b9d0b08d774 /src | |
parent | c9aa77c3f6452154526456497731da1bc8e7d896 (diff) | |
download | binaryen-b0af95200a37d76eccf285dcb45b4ed6162212d0.tar.gz binaryen-b0af95200a37d76eccf285dcb45b4ed6162212d0.tar.bz2 binaryen-b0af95200a37d76eccf285dcb45b4ed6162212d0.zip |
Fuzzer: Distinguish traps from host limitations (#3801)
Host limitations are arbitrary and can be modified by optimizations, so
ignore them. For example, if the optimizer removes allocations then a
host limit on an allocation error may vanish. Or, an optimization that
removes recursion and replaces it with a loop may avoid a host limit
on call depth (that is not done currently, but might some day).
This removes a class of annoying false positives in the fuzzer.
Diffstat (limited to 'src')
-rw-r--r-- | src/shell-interface.h | 13 | ||||
-rw-r--r-- | src/tools/execution-results.h | 12 | ||||
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 4 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 13 |
4 files changed, 40 insertions, 2 deletions
diff --git a/src/shell-interface.h b/src/shell-interface.h index eb0e9f91c..15f600592 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -31,9 +31,17 @@ namespace wasm { +// An exception emitted when exit() is called. struct ExitException {}; + +// An exception emitted when a wasm trap occurs. struct TrapException {}; +// An exception emitted when a host limitation is hit. (These are not wasm traps +// as they are not in the spec; for example, the spec has no limit on how much +// GC memory may be allocated, but hosts have limits.) +struct HostLimitException {}; + struct ShellExternalInterface : ModuleInstance::ExternalInterface { // The underlying memory can be accessed through unaligned pointers which // isn't well-behaved in C++. WebAssembly nonetheless expects it to behave @@ -265,6 +273,11 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { throw TrapException(); } + void hostLimit(const char* why) override { + std::cout << "[host limit " << why << "]\n"; + throw HostLimitException(); + } + void throwException(const WasmException& exn) override { throw exn; } }; diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index a183ad93b..50f627baf 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -90,6 +90,9 @@ struct ExecutionResults { std::map<Name, Literals> results; Loggings loggings; + // If set, we should ignore this and not compare it to anything. + bool ignore = false; + // get results of execution void get(Module& wasm) { LoggingExternalInterface interface(loggings); @@ -176,6 +179,10 @@ struct ExecutionResults { } bool operator==(ExecutionResults& other) { + if (ignore || other.ignore) { + std::cout << "ignoring comparison of ExecutionResults!\n"; + return true; + } for (auto& iter : other.results) { auto name = iter.first; if (results.find(name) == results.end()) { @@ -231,6 +238,11 @@ struct ExecutionResults { return instance.callFunction(func->name, arguments); } catch (const TrapException&) { return {}; + } catch (const HostLimitException&) { + // This should be ignored and not compared with, as optimizations can + // change whether a host limit is reached. + ignore = true; + return {}; } } }; diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 6662dd176..2f7707853 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -312,6 +312,10 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface { throw FailToEvalException(std::string("trap: ") + why); } + void hostLimit(const char* why) override { + throw FailToEvalException(std::string("trap: ") + why); + } + void throwException(const WasmException& exn) override { std::stringstream ss; ss << "exception thrown: " << exn; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index d76f3fabf..37bebdf6b 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -197,7 +197,7 @@ public: Flow visit(Expression* curr) { depth++; if (maxDepth != NO_LIMIT && depth > maxDepth) { - trap("interpreter recursion limit"); + hostLimit("interpreter recursion limit"); } auto ret = OverriddenVisitor<SubType, Flow>::visit(curr); if (!ret.breaking()) { @@ -1622,7 +1622,7 @@ public: // limits on 32-bit machines, and in particular on wasm32 VMs that do not // have 4GB support, so give up there. if (num >= (1 << 30) / sizeof(Literal)) { - trap("allocation failure"); + hostLimit("allocation failure"); } Literals data(num); if (curr->isWithDefault()) { @@ -1739,6 +1739,8 @@ public: virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); } + virtual void hostLimit(const char* why) { WASM_UNREACHABLE("unimp"); } + virtual void throwException(const WasmException& exn) { WASM_UNREACHABLE("unimp"); } @@ -2024,6 +2026,8 @@ public: void trap(const char* why) override { throw NonconstantException(); } + void hostLimit(const char* why) override { throw NonconstantException(); } + virtual void throwException(const WasmException& exn) override { throw NonconstantException(); } @@ -2076,6 +2080,7 @@ public: SubType& instance) = 0; virtual bool growMemory(Address oldSize, Address newSize) = 0; virtual void trap(const char* why) = 0; + virtual void hostLimit(const char* why) = 0; virtual void throwException(const WasmException& exn) = 0; // the default impls for load and store switch on the sizes. you can either @@ -3095,6 +3100,10 @@ private: instance.externalInterface->trap(why); } + void hostLimit(const char* why) override { + instance.externalInterface->hostLimit(why); + } + void throwException(const WasmException& exn) override { instance.externalInterface->throwException(exn); } |