summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wasm-validator.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index e837c2dd6..f78a2301d 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -327,6 +327,63 @@ public:
self->pushTask(visitPoppyExpression, currp);
}
}
+
+ // Also verify that only allowed expressions end up in the situation where
+ // the expression has type unreachable but there is no unreachable child.
+ // For example a Call with no unreachable child cannot be unreachable, but a
+ // Break can be.
+ if (curr->type == Type::unreachable) {
+ switch (curr->_id) {
+ case Expression::BreakId: {
+ // If there is a condition, that is already validated fully in
+ // visitBreak(). If there isn't a condition, then this is allowed to
+ // be unreachable even without an unreachable child. Either way, we
+ // can leave.
+ return;
+ }
+ case Expression::SwitchId:
+ case Expression::ReturnId:
+ case Expression::UnreachableId:
+ case Expression::ThrowId:
+ case Expression::RethrowId: {
+ // These can all be unreachable without an unreachable child.
+ return;
+ }
+ case Expression::CallId: {
+ if (curr->cast<Call>()->isReturn) {
+ return;
+ }
+ break;
+ }
+ case Expression::CallIndirectId: {
+ if (curr->cast<CallIndirect>()->isReturn) {
+ return;
+ }
+ break;
+ }
+ case Expression::CallRefId: {
+ if (curr->cast<CallRef>()->isReturn) {
+ return;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ // If we reach here, then we must have an unreachable child.
+ bool hasUnreachableChild = false;
+ for (auto* child : ChildIterator(curr)) {
+ if (child->type == Type::unreachable) {
+ hasUnreachableChild = true;
+ break;
+ }
+ }
+ self->shouldBeTrue(hasUnreachableChild,
+ curr,
+ "unreachable instruction must have unreachable child");
+ }
}
void noteBreak(Name name, Expression* value, Expression* curr);