Skip to content

Commit da4652b

Browse files
authored
Disallow exact casts without custom descriptors enabled (#7510)
When we emit modules containing exact types without custom descriptors enabled, we generalize those types to be inexact so the written module is valid for the feature set. This fudging of the types changes the behavior of casts, though; casts to exact types that should have failed at runtime may in fact succeed after the binary is written and the cast target type is fudged to be inexact. To avoid the binary writer introducing this change in behavior, disallow casts to exact types when custom descriptors is not enabled. This will require optimizations to avoid introducing casts to exact types when custom descriptors is not enabled. We hypothesize that this will be simpler than the alternative, which would be to have all optimizations (and the interpreter) treat casts to exact types as casts to inexact types when custom descriptors is disabled. Test the new validation errors and and update an existing test that this change invalidates by splitting off the part that depended on custom descriptors being disabled into a separate test.
1 parent 1623ea8 commit da4652b

File tree

5 files changed

+96
-124
lines changed

5 files changed

+96
-124
lines changed

scripts/test/fuzzing.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@
113113
'vacuum-stack-switching.wast',
114114
# TODO: fuzzer support for exact references
115115
'exact-references.wast',
116+
'exact-references-lowering.wast',
117+
'exact-casts.wast',
116118
'optimize-instructions-exact.wast',
117119
'local-subtyping-exact.wast',
118120
'remove-unused-types-exact.wast',

src/wasm/wasm-validator.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,6 +2903,12 @@ void FunctionValidator::visitRefTest(RefTest* curr) {
29032903
curr->ref->type.getHeapType().getBottom(),
29042904
curr,
29052905
"ref.test target type and ref type must have a common supertype");
2906+
2907+
shouldBeTrue(curr->castType.isInexact() ||
2908+
getModule()->features.hasCustomDescriptors(),
2909+
curr,
2910+
"ref.test of exact type requires custom descriptors "
2911+
"[--enable-custom-descriptors]");
29062912
}
29072913

29082914
void FunctionValidator::visitRefCast(RefCast* curr) {
@@ -2941,6 +2947,12 @@ void FunctionValidator::visitRefCast(RefCast* curr) {
29412947
shouldBeTrue(curr->ref->type.isNullable() || curr->type.isNonNullable(),
29422948
curr,
29432949
"ref.cast null of non-nullable references are not allowed");
2950+
2951+
shouldBeTrue(curr->type.isInexact() ||
2952+
getModule()->features.hasCustomDescriptors(),
2953+
curr,
2954+
"ref.cast to exact type requires custom descriptors "
2955+
"[--enable-custom-descriptors]");
29442956
}
29452957

29462958
void FunctionValidator::visitBrOn(BrOn* curr) {
@@ -2970,6 +2982,11 @@ void FunctionValidator::visitBrOn(BrOn* curr) {
29702982
curr->ref->type,
29712983
curr,
29722984
"br_on_cast* target type must be a subtype of its input type");
2985+
shouldBeTrue(curr->castType.isInexact() ||
2986+
getModule()->features.hasCustomDescriptors(),
2987+
curr,
2988+
"br_on_cast* to exact type requires custom descriptors "
2989+
"[--enable-custom-descriptors]");
29732990
} else {
29742991
shouldBeEqual(curr->castType,
29752992
Type(Type::none),
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
3+
;; Check that if we emit a binary without custom descriptors enabled, the exact
4+
;; types are generalized to be inexact.
5+
6+
;; RUN: wasm-opt %s -all --disable-custom-descriptors -g -o %t.noexact.wasm
7+
;; RUN: wasm-opt %t.noexact.wasm -all -S -o - | filecheck %s
8+
9+
(module
10+
;; CHECK: (type $foo (struct (field (ref null $foo)) (field (ref $foo))))
11+
(type $foo (struct (field (ref null (exact $foo)) (ref (exact $foo)))))
12+
13+
;; CHECK: (type $1 (func (param (ref $foo))))
14+
15+
;; CHECK: (global $g (ref null $foo) (ref.null none))
16+
(global $g (ref null (exact $foo)) (ref.null none))
17+
18+
;; CHECK: (func $f (type $1) (param $0 (ref $foo))
19+
;; CHECK-NEXT: (local $1 (ref null $foo))
20+
;; CHECK-NEXT: )
21+
(func $f (param (ref (exact $foo)))
22+
(local (ref null (exact $foo)))
23+
)
24+
)

test/lit/basic/exact-references.wast

Lines changed: 1 addition & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,26 @@
99
;; RUN: cat %t.bin.wast | filecheck %s --check-prefix=CHECK-BIN
1010
;; RUN: cat %t.bin.nodebug.wast | filecheck %s --check-prefix=CHECK-BIN-NODEBUG
1111

12-
;; Also check that if we emit a binary without custom descriptors enabled, the
13-
;; types are generalized to be inexact.
14-
15-
;; RUN: wasm-opt %s -all --disable-custom-descriptors -g -o %t.noexact.wasm
16-
;; RUN: wasm-opt %t.noexact.wasm -all -S -o - | filecheck %s --check-prefix=NO-EXACT
17-
1812
(module
1913
;; CHECK-TEXT: (type $foo (struct (field (ref null (exact $foo))) (field (ref (exact $foo)))))
2014
;; CHECK-BIN: (type $foo (struct (field (ref null (exact $foo))) (field (ref (exact $foo)))))
21-
;; NO-EXACT: (type $foo (struct (field (ref null $foo)) (field (ref $foo))))
2215
(type $foo (struct (field (ref null (exact $foo)) (ref (exact $foo)))))
2316

2417
(rec
2518
;; CHECK-TEXT: (rec
2619
;; CHECK-TEXT-NEXT: (type $super (sub (struct)))
2720
;; CHECK-BIN: (rec
2821
;; CHECK-BIN-NEXT: (type $super (sub (struct)))
29-
;; NO-EXACT: (rec
30-
;; NO-EXACT-NEXT: (type $super (sub (struct)))
3122
(type $super (sub (struct)))
3223
;; CHECK-TEXT: (type $sub1 (sub $super (struct)))
3324
;; CHECK-BIN: (type $sub1 (sub $super (struct)))
34-
;; NO-EXACT: (type $sub1 (sub $super (struct)))
3525
(type $sub1 (sub $super (struct)))
3626
;; CHECK-TEXT: (type $sub2 (sub $super (struct)))
3727
;; CHECK-BIN: (type $sub2 (sub $super (struct)))
38-
;; NO-EXACT: (type $sub2 (sub $super (struct)))
3928
(type $sub2 (sub $super (struct)))
4029
)
4130

31+
4232
;; CHECK-TEXT: (type $4 (func (param (ref null (exact $foo))) (result (ref (exact $foo)))))
4333

4434
;; CHECK-TEXT: (type $5 (func (param (ref null (exact $foo)))))
@@ -61,22 +51,10 @@
6151
;; CHECK-BIN: (type $8 (func (param (ref null (exact $foo))) (result (ref null (exact $foo)))))
6252

6353
;; CHECK-BIN: (import "" "g1" (global $g1 (ref null (exact $foo))))
64-
;; NO-EXACT: (type $4 (func (param (ref null $foo)) (result (ref $foo))))
65-
66-
;; NO-EXACT: (type $5 (func (param (ref null $foo))))
67-
68-
;; NO-EXACT: (type $6 (func (param (ref null $super)) (result (ref null $super))))
69-
70-
;; NO-EXACT: (type $7 (func (param (ref null $sub1))))
71-
72-
;; NO-EXACT: (type $8 (func (param (ref null $foo)) (result (ref null $foo))))
73-
74-
;; NO-EXACT: (import "" "g1" (global $g1 (ref null $foo)))
7554
(import "" "g1" (global $g1 (ref null (exact $foo))))
7655

7756
;; CHECK-TEXT: (import "" "g2" (global $g2 (ref (exact $foo))))
7857
;; CHECK-BIN: (import "" "g2" (global $g2 (ref (exact $foo))))
79-
;; NO-EXACT: (import "" "g2" (global $g2 (ref $foo)))
8058
(import "" "g2" (global $g2 (ref (exact $foo))))
8159

8260
;; CHECK-TEXT: (func $ref-test (type $5) (param $0 (ref null (exact $foo)))
@@ -103,18 +81,6 @@
10381
;; CHECK-BIN-NEXT: )
10482
;; CHECK-BIN-NEXT: )
10583
;; CHECK-BIN-NEXT: )
106-
;; NO-EXACT: (func $ref-test (type $5) (param $0 (ref null $foo))
107-
;; NO-EXACT-NEXT: (drop
108-
;; NO-EXACT-NEXT: (ref.test (ref $foo)
109-
;; NO-EXACT-NEXT: (local.get $0)
110-
;; NO-EXACT-NEXT: )
111-
;; NO-EXACT-NEXT: )
112-
;; NO-EXACT-NEXT: (drop
113-
;; NO-EXACT-NEXT: (ref.test (ref null $foo)
114-
;; NO-EXACT-NEXT: (local.get $0)
115-
;; NO-EXACT-NEXT: )
116-
;; NO-EXACT-NEXT: )
117-
;; NO-EXACT-NEXT: )
11884
(func $ref-test (param (ref null (exact $foo)))
11985
(drop
12086
(ref.test (ref (exact $foo))
@@ -162,23 +128,6 @@
162128
;; CHECK-BIN-NEXT: )
163129
;; CHECK-BIN-NEXT: )
164130
;; CHECK-BIN-NEXT: )
165-
;; NO-EXACT: (func $ref-cast (type $7) (param $0 (ref null $sub1))
166-
;; NO-EXACT-NEXT: (drop
167-
;; NO-EXACT-NEXT: (ref.cast (ref $sub1)
168-
;; NO-EXACT-NEXT: (local.get $0)
169-
;; NO-EXACT-NEXT: )
170-
;; NO-EXACT-NEXT: )
171-
;; NO-EXACT-NEXT: (drop
172-
;; NO-EXACT-NEXT: (ref.cast (ref null $sub1)
173-
;; NO-EXACT-NEXT: (local.get $0)
174-
;; NO-EXACT-NEXT: )
175-
;; NO-EXACT-NEXT: )
176-
;; NO-EXACT-NEXT: (drop
177-
;; NO-EXACT-NEXT: (ref.cast (ref none)
178-
;; NO-EXACT-NEXT: (local.get $0)
179-
;; NO-EXACT-NEXT: )
180-
;; NO-EXACT-NEXT: )
181-
;; NO-EXACT-NEXT: )
182131
(func $ref-cast (param (ref null (exact $sub1)))
183132
(drop
184133
(ref.cast (ref (exact $sub1))
@@ -227,21 +176,6 @@
227176
;; CHECK-BIN-NEXT: (local.get $0)
228177
;; CHECK-BIN-NEXT: )
229178
;; CHECK-BIN-NEXT: )
230-
;; NO-EXACT: (func $br-on-cast (type $6) (param $0 (ref null $super)) (result (ref null $super))
231-
;; NO-EXACT-NEXT: (block $block (result (ref null $super))
232-
;; NO-EXACT-NEXT: (drop
233-
;; NO-EXACT-NEXT: (br_on_cast $block (ref null $super) (ref null $sub1)
234-
;; NO-EXACT-NEXT: (local.get $0)
235-
;; NO-EXACT-NEXT: )
236-
;; NO-EXACT-NEXT: )
237-
;; NO-EXACT-NEXT: (drop
238-
;; NO-EXACT-NEXT: (br_on_cast $block (ref null $super) (ref $sub1)
239-
;; NO-EXACT-NEXT: (local.get $0)
240-
;; NO-EXACT-NEXT: )
241-
;; NO-EXACT-NEXT: )
242-
;; NO-EXACT-NEXT: (local.get $0)
243-
;; NO-EXACT-NEXT: )
244-
;; NO-EXACT-NEXT: )
245179
(func $br-on-cast (param (ref null $super)) (result (ref null $super))
246180
(drop
247181
(br_on_cast 0 anyref (ref null (exact $sub1))
@@ -286,21 +220,6 @@
286220
;; CHECK-BIN-NEXT: (local.get $0)
287221
;; CHECK-BIN-NEXT: )
288222
;; CHECK-BIN-NEXT: )
289-
;; NO-EXACT: (func $br-on-cast-fail (type $6) (param $0 (ref null $super)) (result (ref null $super))
290-
;; NO-EXACT-NEXT: (block $block (result (ref null $super))
291-
;; NO-EXACT-NEXT: (drop
292-
;; NO-EXACT-NEXT: (br_on_cast_fail $block (ref null $super) (ref null $sub1)
293-
;; NO-EXACT-NEXT: (local.get $0)
294-
;; NO-EXACT-NEXT: )
295-
;; NO-EXACT-NEXT: )
296-
;; NO-EXACT-NEXT: (drop
297-
;; NO-EXACT-NEXT: (br_on_cast_fail $block (ref null $super) (ref $sub1)
298-
;; NO-EXACT-NEXT: (local.get $0)
299-
;; NO-EXACT-NEXT: )
300-
;; NO-EXACT-NEXT: )
301-
;; NO-EXACT-NEXT: (local.get $0)
302-
;; NO-EXACT-NEXT: )
303-
;; NO-EXACT-NEXT: )
304223
(func $br-on-cast-fail (param (ref null $super)) (result (ref null $super))
305224
(drop
306225
(br_on_cast_fail 0 anyref (ref null (exact $sub1))
@@ -325,11 +244,6 @@
325244
;; CHECK-BIN-NEXT: (local.get $0)
326245
;; CHECK-BIN-NEXT: )
327246
;; CHECK-BIN-NEXT: )
328-
;; NO-EXACT: (func $valid-ref-as-non-null (type $4) (param $0 (ref null $foo)) (result (ref $foo))
329-
;; NO-EXACT-NEXT: (ref.as_non_null
330-
;; NO-EXACT-NEXT: (local.get $0)
331-
;; NO-EXACT-NEXT: )
332-
;; NO-EXACT-NEXT: )
333247
(func $valid-ref-as-non-null (param (ref null (exact $foo))) (result (ref (exact $foo)))
334248
(ref.as_non_null
335249
(local.get 0)
@@ -356,15 +270,6 @@
356270
;; CHECK-BIN-NEXT: )
357271
;; CHECK-BIN-NEXT: )
358272
;; CHECK-BIN-NEXT: )
359-
;; NO-EXACT: (func $valid-br-on-null (type $5) (param $0 (ref null $foo))
360-
;; NO-EXACT-NEXT: (block $block
361-
;; NO-EXACT-NEXT: (drop
362-
;; NO-EXACT-NEXT: (br_on_null $block
363-
;; NO-EXACT-NEXT: (local.get $0)
364-
;; NO-EXACT-NEXT: )
365-
;; NO-EXACT-NEXT: )
366-
;; NO-EXACT-NEXT: )
367-
;; NO-EXACT-NEXT: )
368273
(func $valid-br-on-null (param (ref null (exact $foo)))
369274
(drop
370275
(block (result (ref (exact $foo)))
@@ -391,14 +296,6 @@
391296
;; CHECK-BIN-NEXT: (unreachable)
392297
;; CHECK-BIN-NEXT: )
393298
;; CHECK-BIN-NEXT: )
394-
;; NO-EXACT: (func $valid-br-on-non-null (type $4) (param $0 (ref null $foo)) (result (ref $foo))
395-
;; NO-EXACT-NEXT: (block $block (result (ref $foo))
396-
;; NO-EXACT-NEXT: (br_on_non_null $block
397-
;; NO-EXACT-NEXT: (local.get $0)
398-
;; NO-EXACT-NEXT: )
399-
;; NO-EXACT-NEXT: (unreachable)
400-
;; NO-EXACT-NEXT: )
401-
;; NO-EXACT-NEXT: )
402299
(func $valid-br-on-non-null (param (ref null (exact $foo))) (result (ref (exact $foo)))
403300
(br_on_non_null 0
404301
(local.get 0)
@@ -428,16 +325,6 @@
428325
;; CHECK-BIN-NEXT: (unreachable)
429326
;; CHECK-BIN-NEXT: )
430327
;; CHECK-BIN-NEXT: )
431-
;; NO-EXACT: (func $valid-br-on-cast (type $8) (param $0 (ref null $foo)) (result (ref null $foo))
432-
;; NO-EXACT-NEXT: (block $block (result (ref null $foo))
433-
;; NO-EXACT-NEXT: (drop
434-
;; NO-EXACT-NEXT: (br_on_cast $block (ref null $foo) (ref null $foo)
435-
;; NO-EXACT-NEXT: (local.get $0)
436-
;; NO-EXACT-NEXT: )
437-
;; NO-EXACT-NEXT: )
438-
;; NO-EXACT-NEXT: (unreachable)
439-
;; NO-EXACT-NEXT: )
440-
;; NO-EXACT-NEXT: )
441328
(func $valid-br-on-cast (param (ref null (exact $foo))) (result (ref null (exact $foo)))
442329
(drop
443330
(block (result (ref (exact $foo)))
@@ -471,16 +358,6 @@
471358
;; CHECK-BIN-NEXT: (unreachable)
472359
;; CHECK-BIN-NEXT: )
473360
;; CHECK-BIN-NEXT: )
474-
;; NO-EXACT: (func $valid-br-on-cast-fail (type $4) (param $0 (ref null $foo)) (result (ref $foo))
475-
;; NO-EXACT-NEXT: (block $block (result (ref $foo))
476-
;; NO-EXACT-NEXT: (drop
477-
;; NO-EXACT-NEXT: (br_on_cast_fail $block (ref null $foo) (ref null $foo)
478-
;; NO-EXACT-NEXT: (local.get $0)
479-
;; NO-EXACT-NEXT: )
480-
;; NO-EXACT-NEXT: )
481-
;; NO-EXACT-NEXT: (unreachable)
482-
;; NO-EXACT-NEXT: )
483-
;; NO-EXACT-NEXT: )
484361
(func $valid-br-on-cast-fail (param (ref null (exact $foo))) (result (ref (exact $foo)))
485362
(drop
486363
(block (result (ref null (exact $foo)))

test/lit/validation/exact-casts.wast

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
;; Test that casting to exact types without custom descriptors is a validation
2+
;; error.
3+
4+
;; RUN: not wasm-opt %s -all --disable-custom-descriptors 2>&1 | filecheck %s
5+
6+
;; CHECK: [wasm-validator error in function ref.cast] unexpected false: ref.cast to exact type requires custom descriptors [--enable-custom-descriptors],
7+
8+
;; CHECK: [wasm-validator error in function ref.test] unexpected false: ref.test of exact type requires custom descriptors [--enable-custom-descriptors],
9+
10+
;; CHECK: [wasm-validator error in function br_on_cast] unexpected false: br_on_cast* to exact type requires custom descriptors [--enable-custom-descriptors],
11+
12+
;; CHECK: [wasm-validator error in function br_on_cast_fail] unexpected false: br_on_cast* to exact type requires custom descriptors [--enable-custom-descriptors],
13+
14+
(module
15+
(type $foo (struct))
16+
17+
(func $ref.cast (param anyref)
18+
(drop
19+
(ref.cast (ref null (exact $foo))
20+
(local.get 0)
21+
)
22+
)
23+
)
24+
25+
(func $ref.test (param anyref)
26+
(drop
27+
(ref.test (ref (exact $foo))
28+
(local.get 0)
29+
)
30+
)
31+
)
32+
33+
(func $br_on_cast (param anyref)
34+
(drop
35+
(block (result anyref)
36+
(br_on_cast 0 anyref (ref null (exact $foo))
37+
(local.get 0)
38+
)
39+
)
40+
)
41+
)
42+
43+
(func $br_on_cast_fail (param anyref)
44+
(drop
45+
(block (result anyref)
46+
(br_on_cast_fail 0 anyref (ref (exact $foo))
47+
(local.get 0)
48+
)
49+
)
50+
)
51+
)
52+
)

0 commit comments

Comments
 (0)