Skip to content

Commit bc47696

Browse files
authored
Validate that allocations produce non-nullable references (#7346)
For `struct.new`, `array.new`, `ref.func`, `ref.i31`, `cont.new`, and `cont.bind`, check in the validator that the result type is a non-nullable reference. This ensures that we have the most precise possible type information for these instructions. The generic stale type checker does not check this because finalizing these expressions does not change their types.
1 parent dc055a8 commit bc47696

File tree

1 file changed

+61
-12
lines changed

1 file changed

+61
-12
lines changed

src/wasm/wasm-validator.cpp

+61-12
Original file line numberDiff line numberDiff line change
@@ -2355,6 +2355,11 @@ void FunctionValidator::visitRefFunc(RefFunc* curr) {
23552355
shouldBeTrue(!getFunction() || getModule()->features.hasReferenceTypes(),
23562356
curr,
23572357
"ref.func requires reference-types [--enable-reference-types]");
2358+
if (!shouldBeTrue(curr->type.isNonNullable(),
2359+
curr,
2360+
"ref.func should have a non-nullable reference type")) {
2361+
return;
2362+
}
23582363
if (!info.validateGlobally) {
23592364
return;
23602365
}
@@ -2372,7 +2377,6 @@ void FunctionValidator::visitRefFunc(RefFunc* curr) {
23722377
// API (for now those users create the type with funcref). This also needs to
23732378
// be fixed in LegalizeJSInterface and FuncCastEmulation and other places that
23742379
// update function types.
2375-
// TODO: check for non-nullability
23762380
}
23772381

23782382
void FunctionValidator::visitRefEq(RefEq* curr) {
@@ -2843,16 +2847,33 @@ void FunctionValidator::visitCallRef(CallRef* curr) {
28432847
void FunctionValidator::visitRefI31(RefI31* curr) {
28442848
shouldBeTrue(
28452849
getModule()->features.hasGC(), curr, "ref.i31 requires gc [--enable-gc]");
2846-
if (curr->type.isRef() && curr->type.getHeapType().isShared()) {
2850+
shouldBeSubType(curr->value->type,
2851+
Type::i32,
2852+
curr->value,
2853+
"ref.i31's argument should be i32");
2854+
2855+
if (curr->type == Type::unreachable) {
2856+
return;
2857+
}
2858+
2859+
if (!shouldBeTrue(curr->type.isNonNullable(),
2860+
curr,
2861+
"ref.i31 should have a non-nullable reference type")) {
2862+
return;
2863+
}
2864+
auto heapType = curr->type.getHeapType();
2865+
if (!shouldBeTrue(heapType.isBasic() &&
2866+
heapType.getBasic(Unshared) == HeapType::i31,
2867+
curr,
2868+
"ref.i31 should have an i31 reference type")) {
2869+
return;
2870+
}
2871+
if (heapType.isShared()) {
28472872
shouldBeTrue(
28482873
getModule()->features.hasSharedEverything(),
28492874
curr,
28502875
"ref.i31_shared requires shared-everything [--enable-shared-everything]");
28512876
}
2852-
shouldBeSubType(curr->value->type,
2853-
Type::i32,
2854-
curr->value,
2855-
"ref.i31's argument should be i32");
28562877
}
28572878

28582879
void FunctionValidator::visitI31Get(I31Get* curr) {
@@ -2967,6 +2988,11 @@ void FunctionValidator::visitStructNew(StructNew* curr) {
29672988
if (curr->type == Type::unreachable) {
29682989
return;
29692990
}
2991+
if (!shouldBeTrue(curr->type.isNonNullable(),
2992+
curr,
2993+
"struct.new should have a non-nullable reference type")) {
2994+
return;
2995+
}
29702996
auto heapType = curr->type.getHeapType();
29712997
if (!shouldBeTrue(
29722998
heapType.isStruct(), curr, "struct.new heap type must be struct")) {
@@ -3200,6 +3226,11 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) {
32003226
if (curr->type == Type::unreachable) {
32013227
return;
32023228
}
3229+
if (!shouldBeTrue(curr->type.isNonNullable(),
3230+
curr,
3231+
"array.new should have a non-nullable reference type")) {
3232+
return;
3233+
}
32033234
auto heapType = curr->type.getHeapType();
32043235
if (!shouldBeTrue(
32053236
heapType.isArray(), curr, "array.new heap type must be array")) {
@@ -3630,12 +3661,20 @@ void FunctionValidator::visitContNew(ContNew* curr) {
36303661
curr,
36313662
"cont.new requires stack-switching [--enable-stack-switching]");
36323663

3633-
shouldBeTrue(
3634-
(curr->type.isContinuation() &&
3635-
curr->type.getHeapType().getContinuation().type.isSignature()) ||
3636-
curr->type == Type::unreachable,
3637-
curr,
3638-
"cont.new must be annotated with a continuation type");
3664+
if (curr->type == Type::unreachable) {
3665+
return;
3666+
}
3667+
3668+
if (!shouldBeTrue(curr->type.isNonNullable(),
3669+
curr,
3670+
"cont.new should have a non-nullable reference type")) {
3671+
return;
3672+
}
3673+
3674+
shouldBeTrue(curr->type.isContinuation() &&
3675+
curr->type.getHeapType().getContinuation().type.isSignature(),
3676+
curr,
3677+
"cont.new must be annotated with a continuation type");
36393678
}
36403679

36413680
void FunctionValidator::visitContBind(ContBind* curr) {
@@ -3657,6 +3696,16 @@ void FunctionValidator::visitContBind(ContBind* curr) {
36573696
curr->type == Type::unreachable,
36583697
curr,
36593698
"the second type annotation on cont.bind must be a continuation type");
3699+
3700+
if (curr->type == Type::unreachable) {
3701+
return;
3702+
}
3703+
3704+
if (!shouldBeTrue(curr->type.isNonNullable(),
3705+
curr,
3706+
"cont.bind should have a non-nullable reference type")) {
3707+
return;
3708+
}
36603709
}
36613710

36623711
void FunctionValidator::visitSuspend(Suspend* curr) {

0 commit comments

Comments
 (0)