Skip to content

Commit bb290e7

Browse files
authored
Fix assertion in br_on_cast finalization (#8476)
If the br_on_cast is invalid because its input and output types are unrelated, the GLB used as the new cast type will be unreachable. This caused an assertion that the GLB was a reference to fail. Bail out early in this case and leave the unreachable cast type for the validator to find.
1 parent 9b1d22d commit bb290e7

3 files changed

Lines changed: 58 additions & 21 deletions

File tree

src/wasm/wasm-validator.cpp

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3124,8 +3124,8 @@ void FunctionValidator::visitRefTest(RefTest* curr) {
31243124
return;
31253125
}
31263126
shouldBeEqual(
3127-
curr->castType.getHeapType().getBottom(),
3128-
curr->ref->type.getHeapType().getBottom(),
3127+
HeapType(curr->castType.getHeapType().getTop()),
3128+
HeapType(curr->ref->type.getHeapType().getTop()),
31293129
curr,
31303130
"ref.test target type and ref type must have a common supertype");
31313131

@@ -3168,27 +3168,15 @@ void FunctionValidator::visitRefCast(RefCast* curr) {
31683168
curr->ref->type.isRef(), curr, "ref.cast ref must have ref type")) {
31693169
return;
31703170
}
3171-
// If the cast is unreachable but not the ref (we ruled out the former
3172-
// earlier), then the cast is unreachable because the cast type had no
3173-
// common supertype with the ref, which is invalid. This is the same as the
3174-
// check below us, but we must do it first (as getHeapType fails otherwise).
3175-
if (!shouldBeUnequal(
3176-
curr->type,
3177-
Type(Type::unreachable),
3178-
curr,
3179-
"ref.cast target type and ref type must have a common supertype")) {
3180-
return;
3181-
}
31823171
// Also error (more generically) on i32 and anything else invalid here.
31833172
if (!shouldBeTrue(curr->type.isRef(), curr, "ref.cast must have ref type")) {
31843173
return;
31853174
}
31863175
shouldBeEqual(
3187-
curr->type.getHeapType().getBottom(),
3188-
curr->ref->type.getHeapType().getBottom(),
3176+
HeapType(curr->type.getHeapType().getTop()),
3177+
HeapType(curr->ref->type.getHeapType().getTop()),
31893178
curr,
31903179
"ref.cast target type and ref type must have a common supertype");
3191-
31923180
// We should never have a nullable cast of a non-nullable reference, since
31933181
// that unnecessarily loses type information.
31943182
shouldBeTrue(curr->ref->type.isNullable() || curr->type.isNonNullable(),
@@ -3260,8 +3248,8 @@ void FunctionValidator::visitBrOn(BrOn* curr) {
32603248
}
32613249
if (curr->ref->type != Type::unreachable) {
32623250
shouldBeEqual(
3263-
curr->castType.getHeapType().getBottom(),
3264-
curr->ref->type.getHeapType().getBottom(),
3251+
HeapType(curr->castType.getHeapType().getTop()),
3252+
HeapType(curr->ref->type.getHeapType().getTop()),
32653253
curr,
32663254
"br_on_cast* target type and ref type must have a common supertype");
32673255
}

src/wasm/wasm.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,12 @@ void RefTest::finalize() {
10601060
} else {
10611061
type = Type::i32;
10621062
// Do not unnecessarily lose type information.
1063-
castType = Type::getGreatestLowerBound(castType, ref->type);
1063+
auto newCastType = Type::getGreatestLowerBound(castType, ref->type);
1064+
if (newCastType == Type::unreachable) {
1065+
// This is invalid. Leave the existing types for the validator to catch.
1066+
return;
1067+
}
1068+
castType = newCastType;
10641069
}
10651070
}
10661071

@@ -1092,7 +1097,8 @@ void RefCast::finalize() {
10921097

10931098
// We reach this before validation, so the input type might be totally wrong.
10941099
// Return early in this case to avoid doing the wrong thing below.
1095-
if (!ref->type.isRef()) {
1100+
if (!ref->type.isRef() || !type.isRef() ||
1101+
ref->type.getHeapType().getTop() != type.getHeapType().getTop()) {
10961102
return;
10971103
}
10981104

@@ -1131,7 +1137,14 @@ void BrOn::finalize() {
11311137
// cast type, we can improve the cast type in a way that will not change the
11321138
// cast behavior. This satisfies the constraint we had before Custom
11331139
// Descriptors that the cast type is a subtype of the input type.
1134-
castType = Type::getGreatestLowerBound(castType, ref->type);
1140+
auto newCastType = Type::getGreatestLowerBound(castType, ref->type);
1141+
if (newCastType == Type::unreachable) {
1142+
// This is not valid. Leave the original cast type in place for the
1143+
// validator to catch.
1144+
type = ref->type;
1145+
return;
1146+
}
1147+
castType = newCastType;
11351148
assert(castType.isRef());
11361149
} else if (op == BrOnCastDescEq || op == BrOnCastDescEqFail) {
11371150
if (desc->type.isNull()) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
;; RUN: not wasm-opt %s --all-features 2>&1 | filecheck %s
2+
3+
(module
4+
(type $shared (shared (struct)))
5+
(type $unshared (struct))
6+
7+
(func $test-shared-to-unshared (param $s (ref $shared))
8+
;; CHECK: [wasm-validator error in function test-shared-to-unshared] any != (shared any): ref.test target type and ref type must have a common supertype
9+
(drop
10+
(ref.test (ref $unshared)
11+
(local.get $s)
12+
)
13+
)
14+
)
15+
16+
(func $cast-shared-to-unshared (param $s (ref $shared))
17+
;; CHECK: [wasm-validator error in function cast-shared-to-unshared] any != (shared any): ref.cast target type and ref type must have a common supertype
18+
(drop
19+
(ref.cast (ref $unshared)
20+
(local.get $s)
21+
)
22+
)
23+
)
24+
25+
(func $br_on_shared-to-unshared (param $s (ref $shared))
26+
(block $l (result (ref $unshared))
27+
;; CHECK: [wasm-validator error in function br_on_shared-to-unshared] any != (shared any): br_on_cast* target type and ref type must have a common supertype
28+
(drop
29+
(br_on_cast $l (ref $shared) (ref $unshared)
30+
(local.get $s)
31+
)
32+
)
33+
(unreachable)
34+
)
35+
)
36+
)

0 commit comments

Comments
 (0)