Skip to content

Commit 91f38e9

Browse files
authored
[Stack Switching] Fix validation of cont.* that receive nullref inputs (#7809)
1 parent 8d4f96e commit 91f38e9

File tree

3 files changed

+131
-24
lines changed

3 files changed

+131
-24
lines changed

src/wasm/wasm-stack.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2770,14 +2770,20 @@ void BinaryInstWriter::visitSuspend(Suspend* curr) {
27702770
}
27712771

27722772
void BinaryInstWriter::visitContBind(ContBind* curr) {
2773-
assert(curr->cont->type.isContinuation() && curr->type.isContinuation());
2773+
if (curr->cont->type.isNull()) {
2774+
emitUnreachable();
2775+
return;
2776+
}
27742777
o << int8_t(BinaryConsts::ContBind);
27752778
parent.writeIndexedHeapType(curr->cont->type.getHeapType());
27762779
parent.writeIndexedHeapType(curr->type.getHeapType());
27772780
}
27782781

27792782
void BinaryInstWriter::visitResume(Resume* curr) {
2780-
assert(curr->cont->type.isContinuation());
2783+
if (curr->cont->type.isNull()) {
2784+
emitUnreachable();
2785+
return;
2786+
}
27812787
o << int8_t(BinaryConsts::Resume);
27822788
parent.writeIndexedHeapType(curr->cont->type.getHeapType());
27832789

@@ -2798,7 +2804,10 @@ void BinaryInstWriter::visitResume(Resume* curr) {
27982804
}
27992805

28002806
void BinaryInstWriter::visitResumeThrow(ResumeThrow* curr) {
2801-
assert(curr->cont->type.isContinuation());
2807+
if (curr->cont->type.isNull()) {
2808+
emitUnreachable();
2809+
return;
2810+
}
28022811
o << int8_t(BinaryConsts::ResumeThrow);
28032812
parent.writeIndexedHeapType(curr->cont->type.getHeapType());
28042813
o << U32LEB(parent.getTagIndex(curr->tag));
@@ -2820,7 +2829,10 @@ void BinaryInstWriter::visitResumeThrow(ResumeThrow* curr) {
28202829
}
28212830

28222831
void BinaryInstWriter::visitStackSwitch(StackSwitch* curr) {
2823-
assert(curr->cont->type.isContinuation());
2832+
if (curr->cont->type.isNull()) {
2833+
emitUnreachable();
2834+
return;
2835+
}
28242836
o << int8_t(BinaryConsts::Switch);
28252837
parent.writeIndexedHeapType(curr->cont->type.getHeapType());
28262838
o << U32LEB(parent.getTagIndex(curr->tag));

src/wasm/wasm-validator.cpp

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3991,24 +3991,27 @@ void FunctionValidator::visitContBind(ContBind* curr) {
39913991
curr,
39923992
"cont.bind requires stack-switching [--enable-stack-switching]");
39933993

3994+
if (curr->cont->type.isRef() &&
3995+
curr->cont->type.getHeapType().isMaybeShared(HeapType::nocont)) {
3996+
return;
3997+
}
3998+
3999+
if (curr->type == Type::unreachable) {
4000+
return;
4001+
}
4002+
39944003
shouldBeTrue(
3995-
(curr->cont->type.isContinuation() &&
3996-
curr->cont->type.getHeapType().getContinuation().type.isSignature()) ||
3997-
curr->cont->type == Type::unreachable,
4004+
curr->cont->type.isContinuation() &&
4005+
curr->cont->type.getHeapType().getContinuation().type.isSignature(),
39984006
curr,
39994007
"the first type annotation on cont.bind must be a continuation type");
40004008

40014009
shouldBeTrue(
4002-
(curr->type.isContinuation() &&
4003-
curr->type.getHeapType().getContinuation().type.isSignature()) ||
4004-
curr->type == Type::unreachable,
4010+
curr->type.isContinuation() &&
4011+
curr->type.getHeapType().getContinuation().type.isSignature(),
40054012
curr,
40064013
"the second type annotation on cont.bind must be a continuation type");
40074014

4008-
if (curr->type == Type::unreachable) {
4009-
return;
4010-
}
4011-
40124015
if (!shouldBeTrue(curr->type.isNonNullable(),
40134016
curr,
40144017
"cont.bind should have a non-nullable reference type")) {
@@ -4035,6 +4038,11 @@ void FunctionValidator::visitResume(Resume* curr) {
40354038
curr,
40364039
"sentTypes cache in resume instruction has not been initialized");
40374040

4041+
if (curr->cont->type.isRef() &&
4042+
curr->cont->type.getHeapType().isMaybeShared(HeapType::nocont)) {
4043+
return;
4044+
}
4045+
40384046
shouldBeTrue(
40394047
(curr->cont->type.isContinuation() &&
40404048
curr->cont->type.getHeapType().getContinuation().type.isSignature()) ||
@@ -4057,17 +4065,22 @@ void FunctionValidator::visitResumeThrow(ResumeThrow* curr) {
40574065
curr,
40584066
"sentTypes cache in resume_throw instruction has not been initialized");
40594067

4068+
auto* tag = getModule()->getTagOrNull(curr->tag);
4069+
if (!shouldBeTrue(!!tag, curr, "resume_throw exception tag must exist")) {
4070+
return;
4071+
}
4072+
4073+
if (curr->cont->type.isRef() &&
4074+
curr->cont->type.getHeapType().isMaybeShared(HeapType::nocont)) {
4075+
return;
4076+
}
4077+
40604078
shouldBeTrue(
40614079
(curr->cont->type.isContinuation() &&
40624080
curr->cont->type.getHeapType().getContinuation().type.isSignature()) ||
40634081
curr->type == Type::unreachable,
40644082
curr,
40654083
"resume_throw must be annotated with a continuation type");
4066-
4067-
auto* tag = getModule()->getTagOrNull(curr->tag);
4068-
if (!shouldBeTrue(!!tag, curr, "resume_throw must be annotated with a tag")) {
4069-
return;
4070-
}
40714084
}
40724085

40734086
void FunctionValidator::visitStackSwitch(StackSwitch* curr) {
@@ -4076,17 +4089,22 @@ void FunctionValidator::visitStackSwitch(StackSwitch* curr) {
40764089
curr,
40774090
"switch requires stack-switching [--enable-stack-switching]");
40784091

4092+
auto* tag = getModule()->getTagOrNull(curr->tag);
4093+
if (!shouldBeTrue(!!tag, curr, "switch tag must exist")) {
4094+
return;
4095+
}
4096+
4097+
if (curr->cont->type.isRef() &&
4098+
curr->cont->type.getHeapType().isMaybeShared(HeapType::nocont)) {
4099+
return;
4100+
}
4101+
40794102
shouldBeTrue(
40804103
(curr->cont->type.isContinuation() &&
40814104
curr->cont->type.getHeapType().getContinuation().type.isSignature()) ||
40824105
curr->type == Type::unreachable,
40834106
curr,
40844107
"switch must be annotated with a continuation type");
4085-
4086-
auto* tag = getModule()->getTagOrNull(curr->tag);
4087-
if (!shouldBeTrue(!!tag, curr, "switch must be annotated with a tag")) {
4088-
return;
4089-
}
40904108
}
40914109

40924110
void FunctionValidator::visitFunction(Function* curr) {

test/spec/cont.wast

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,80 @@
564564

565565
(assert_return (invoke "sum" (i64.const 10) (i64.const 20)) (i64.const 165))
566566

567+
;; Subtyping
568+
(module
569+
(type $ft1 (func (param i32)))
570+
(type $ct1 (sub (cont $ft1)))
571+
572+
(type $ft0 (func))
573+
(type $ct0 (sub (cont $ft0)))
574+
575+
(func $test (param $x (ref $ct1))
576+
(i32.const 123)
577+
(local.get $x)
578+
(cont.bind $ct1 $ct0)
579+
(drop)
580+
)
581+
)
582+
583+
(module
584+
(type $f1 (sub (func (result anyref))))
585+
(type $f2 (sub $f1 (func (result eqref))))
586+
(type $c1 (sub (cont $f1)))
587+
(type $c2 (sub $c1 (cont $f2)))
588+
)
589+
590+
;; Globals
591+
(module
592+
(type $ft (func))
593+
(type $ct (cont $ft))
594+
595+
(global $k (mut (ref null $ct)) (ref.null $ct))
596+
(global $g (ref null $ct) (ref.null $ct))
597+
598+
(func $f)
599+
(elem declare func $f)
600+
601+
(func (export "set-global")
602+
(global.set $k (cont.new $ct (ref.func $f))))
603+
)
604+
(assert_return (invoke "set-global"))
605+
606+
(assert_invalid
607+
(module
608+
(rec
609+
(type $ft (func (param (ref null $ct))))
610+
(type $ct (cont $ft)))
611+
(type $ft2 (func))
612+
(type $ct2 (cont $ft2))
613+
614+
(tag $swap)
615+
(func $f (type $ft)
616+
(switch $ct $swap (cont.new $ct2 (ref.null $ft2)))
617+
(drop)))
618+
"type mismatch")
619+
620+
(module
621+
(rec
622+
(type $ft (func (param (ref null $ct))))
623+
(type $ct (cont $ft)))
624+
625+
(tag $t)
626+
627+
(func
628+
(cont.new $ct (ref.null $ft))
629+
(unreachable))
630+
(func
631+
(cont.bind $ct $ct (ref.null $ct))
632+
(unreachable))
633+
(func
634+
(resume $ct (ref.null $ct) (ref.null $ct))
635+
(unreachable))
636+
(func
637+
(resume_throw $ct $t (ref.null $ct))
638+
(unreachable))
639+
(func
640+
(switch $ct $t (ref.null $ct))
641+
(unreachable))
642+
)
643+

0 commit comments

Comments
 (0)