diff options
author | Heejin Ahn <aheejin@gmail.com> | 2021-11-08 22:44:29 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-08 22:44:29 -0800 |
commit | 1ad4e23342ef83b9210ce81bbf119047e08b6f3b (patch) | |
tree | 652dd07126bb7251cb7d3811fefb968ae684f173 /src/wasm/wasm-validator.cpp | |
parent | 31a5bf7ad7dbe30ec47766271ba13276117f98a0 (diff) | |
download | binaryen-1ad4e23342ef83b9210ce81bbf119047e08b6f3b.tar.gz binaryen-1ad4e23342ef83b9210ce81bbf119047e08b6f3b.tar.bz2 binaryen-1ad4e23342ef83b9210ce81bbf119047e08b6f3b.zip |
[EH] Improve catch validation (#4315)
This improves validation of `catch` bodies mostly by checking the
validity of `pop`s.
For every `catch` body:
- Checks if its tag exists
- If the tag's type is none:
- Ensures there shouldn't be any `pop`s
- If the tag's type is not none:
- Checks if there's a single `pop` within the catch body
- Checks if the tag type matches the `pop`'s type
- Checks if the `pop`'s location is valid
For every `catch_all` body:
- Ensures there shuldn't be any `pop`s
This uncovers several bugs related to `pop`s in existing tests, which
this PR also fixes.
Diffstat (limited to 'src/wasm/wasm-validator.cpp')
-rw-r--r-- | src/wasm/wasm-validator.cpp | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index bb0e99cc2..86b537bf5 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -19,6 +19,7 @@ #include <sstream> #include <unordered_set> +#include "ir/eh-utils.h" #include "ir/features.h" #include "ir/global-utils.h" #include "ir/intrinsics.h" @@ -2143,6 +2144,70 @@ void FunctionValidator::visitTry(Try* curr) { curr, "try cannot have both catch and delegate at the same time"); + // Given a catch body, find pops corresponding to the catch + auto findPops = [](Expression* expr) { + SmallVector<Pop*, 1> pops; + SmallVector<Expression*, 8> work; + work.push_back(expr); + while (!work.empty()) { + auto* curr = work.back(); + work.pop_back(); + if (auto* pop = curr->dynCast<Pop>()) { + pops.push_back(pop); + } else if (auto* try_ = curr->dynCast<Try>()) { + // We don't go into inner catch bodies; pops in inner catch bodies + // belong to the inner catches + work.push_back(try_->body); + } else { + for (auto* child : ChildIterator(curr)) { + work.push_back(child); + } + } + } + return pops; + }; + + for (Index i = 0; i < curr->catchTags.size(); i++) { + Name tagName = curr->catchTags[i]; + auto* tag = getModule()->getTagOrNull(tagName); + if (!shouldBeTrue(tag != nullptr, curr, "")) { + getStream() << "tag name is invalid: " << tagName << "\n"; + } + + auto* catchBody = curr->catchBodies[i]; + SmallVector<Pop*, 1> pops = findPops(catchBody); + if (tag->sig.params == Type::none) { + if (!shouldBeTrue(pops.empty(), curr, "")) { + getStream() << "catch's tag (" << tagName + << ") doesn't have any params, but there are pops"; + } + } else { + if (shouldBeTrue(pops.size() == 1, curr, "")) { + auto* pop = *pops.begin(); + if (!shouldBeSubType(pop->type, tag->sig.params, curr, "")) { + getStream() + << "catch's tag (" << tagName + << ")'s pop doesn't have the same type as the tag's params"; + } + if (!shouldBeTrue(EHUtils::isPopValid(catchBody), curr, "")) { + getStream() << "catch's body (" << tagName + << ")'s pop's location is not valid"; + } + } else { + getStream() << "catch's tag (" << tagName + << ") has params, so there should be a single pop within " + "the catch body"; + } + } + } + + if (curr->hasCatchAll()) { + auto* catchAllBody = curr->catchBodies.back(); + shouldBeTrue(findPops(catchAllBody).empty(), + curr, + "catch_all's body should not have pops"); + } + if (curr->isDelegate()) { noteDelegate(curr->delegateTarget, curr); } |