From 1ad4e23342ef83b9210ce81bbf119047e08b6f3b Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 8 Nov 2021 22:44:29 -0800 Subject: [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. --- src/wasm/wasm-validator.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'src/wasm/wasm-validator.cpp') 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 #include +#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 pops; + SmallVector work; + work.push_back(expr); + while (!work.empty()) { + auto* curr = work.back(); + work.pop_back(); + if (auto* pop = curr->dynCast()) { + pops.push_back(pop); + } else if (auto* try_ = curr->dynCast()) { + // 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 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); } -- cgit v1.2.3