diff options
author | Heejin Ahn <aheejin@gmail.com> | 2023-12-20 10:48:42 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-20 10:48:42 -0800 |
commit | 11e3af054a1fd137a892499ee0d5813f6c15d07e (patch) | |
tree | 05c06daaac433b6461880c7006982adf91ec3622 /src/wasm/wasm-validator.cpp | |
parent | eb5666eeb0a2b74314e1aaf27e57193cb8fd4a99 (diff) | |
download | binaryen-11e3af054a1fd137a892499ee0d5813f6c15d07e.tar.gz binaryen-11e3af054a1fd137a892499ee0d5813f6c15d07e.tar.bz2 binaryen-11e3af054a1fd137a892499ee0d5813f6c15d07e.zip |
[EH] Add validation for new instructions (#6185)
This adds validation for the new EH instructions (`try_table` and
`throw_ref`):
https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md
This also adds a spec test for checking invalid modules. We cannot check
the executions yet because we don't have the interpreter implementation.
The new test file also contains tests for the existing `throw`, because
this is meant to replace the old spec test someday.
Diffstat (limited to 'src/wasm/wasm-validator.cpp')
-rw-r--r-- | src/wasm/wasm-validator.cpp | 83 |
1 files changed, 78 insertions, 5 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 8c165b700..7ea8b0bdb 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2451,7 +2451,75 @@ void FunctionValidator::visitTry(Try* curr) { } void FunctionValidator::visitTryTable(TryTable* curr) { - // TODO + shouldBeTrue( + getModule()->features.hasExceptionHandling(), + curr, + "try_table requires exception-handling [--enable-exception-handling]"); + if (curr->type != Type::unreachable) { + shouldBeSubType(curr->body->type, + curr->type, + curr->body, + "try_table's type does not match try_table body's type"); + } + + shouldBeEqual(curr->catchTags.size(), + curr->catchDests.size(), + curr, + "the number of catch tags and catch destinations do not match"); + shouldBeEqual(curr->catchTags.size(), + curr->catchRefs.size(), + curr, + "the number of catch tags and catch refs do not match"); + shouldBeEqual(curr->catchTags.size(), + curr->sentTypes.size(), + curr, + "the number of catch tags and sent types do not match"); + + const char* invalidSentTypeMsg = "invalid catch sent type information"; + Type exnref = Type(HeapType::exn, Nullable); + for (Index i = 0; i < curr->catchTags.size(); i++) { + auto sentType = curr->sentTypes[i]; + size_t tagTypeSize; + + Name tagName = curr->catchTags[i]; + if (!tagName) { // catch_all or catch_all_ref + tagTypeSize = 0; + } else { // catch or catch_ref + // Check tag validity + auto* tag = getModule()->getTagOrNull(tagName); + if (!shouldBeTrue(tag != nullptr, curr, "")) { + getStream() << "catch's tag name is invalid: " << tagName << "\n"; + } else if (!shouldBeEqual(tag->sig.results, Type(Type::none), curr, "")) { + getStream() + << "catch's tag (" << tagName + << ") has result values, which is not allowed for exception handling"; + } + + // tagType and sentType should be the same (except for the possible exnref + // at the end of sentType) + auto tagType = tag->sig.params; + tagTypeSize = tagType.size(); + for (Index j = 0; j < tagType.size(); j++) { + shouldBeEqual(tagType[j], sentType[j], curr, invalidSentTypeMsg); + } + } + + // If this is catch_ref or catch_all_ref, sentType.size() should be + // tagType.size() + 1 because there is an exrnef tacked at the end. If + // this is catch/catch_all, the two sizes should be the same. + if (curr->catchRefs[i]) { + if (shouldBeTrue( + sentType.size() == tagTypeSize + 1, curr, invalidSentTypeMsg)) { + shouldBeEqual( + sentType[sentType.size() - 1], exnref, curr, invalidSentTypeMsg); + } + } else { + shouldBeTrue(sentType.size() == tagTypeSize, curr, invalidSentTypeMsg); + } + + // Note catch destinations with sent types + noteBreak(curr->catchDests[i], curr->sentTypes[i], curr); + } } void FunctionValidator::visitThrow(Throw* curr) { @@ -2475,9 +2543,10 @@ void FunctionValidator::visitThrow(Throw* curr) { Type(Type::none), curr, "tags with result types must not be used for exception handling"); - if (!shouldBeTrue(curr->operands.size() == tag->sig.params.size(), - curr, - "tag's param numbers must match")) { + if (!shouldBeEqual(curr->operands.size(), + tag->sig.params.size(), + curr, + "tag's param numbers must match")) { return; } size_t i = 0; @@ -2529,7 +2598,11 @@ void FunctionValidator::visitTupleMake(TupleMake* curr) { } void FunctionValidator::visitThrowRef(ThrowRef* curr) { - // TODO + Type exnref = Type(HeapType::exn, Nullable); + shouldBeSubType(curr->exnref->type, + exnref, + curr, + "throw_ref's argument should be a subtype of exnref"); } void FunctionValidator::visitTupleExtract(TupleExtract* curr) { |