@@ -44,36 +44,89 @@ impl super::Validator {
44
44
ref diagnostic_filter_leaf,
45
45
} = module;
46
46
47
- // NOTE: Types being first is important. All other forms of validation depend on this.
48
- for ( this_handle, ty) in types. iter ( ) {
49
- match ty. inner {
50
- crate :: TypeInner :: Scalar { .. }
51
- | crate :: TypeInner :: Vector { .. }
52
- | crate :: TypeInner :: Matrix { .. }
53
- | crate :: TypeInner :: ValuePointer { .. }
54
- | crate :: TypeInner :: Atomic { .. }
55
- | crate :: TypeInner :: Image { .. }
56
- | crate :: TypeInner :: Sampler { .. }
57
- | crate :: TypeInner :: AccelerationStructure
58
- | crate :: TypeInner :: RayQuery => ( ) ,
59
- crate :: TypeInner :: Pointer { base, space : _ } => {
60
- this_handle. check_dep ( base) ?;
61
- }
62
- crate :: TypeInner :: Array { base, .. }
63
- | crate :: TypeInner :: BindingArray { base, .. } => {
64
- this_handle. check_dep ( base) ?;
65
- }
66
- crate :: TypeInner :: Struct {
67
- ref members,
68
- span : _,
69
- } => {
70
- this_handle. check_dep_iter ( members. iter ( ) . map ( |m| m. ty ) ) ?;
47
+ // Because types can refer to global expressions and vice versa, to
48
+ // ensure the overall structure is free of cycles, we must traverse them
49
+ // both in tandem.
50
+ //
51
+ // Try to visit all types and global expressions in an order such that
52
+ // each item refers only to previously visited items. If we succeed,
53
+ // that shows that there cannot be any cycles, since walking any edge
54
+ // advances you towards the beginning of the visiting order.
55
+ //
56
+ // Validate all the handles in types and expressions as we traverse the
57
+ // arenas.
58
+ let mut global_exprs_iter = global_expressions. iter ( ) . peekable ( ) ;
59
+ for ( th, t) in types. iter ( ) {
60
+ // Imagine the `for` loop and `global_exprs_iter` as two fingers
61
+ // walking the type and global expression arenas. They don't visit
62
+ // elements at the same rate: sometimes one processes a bunch of
63
+ // elements while the other one stays still. But at each point, they
64
+ // check that the two ranges of elements they've visited only refer
65
+ // to other elements in those ranges.
66
+ //
67
+ // For brevity, we'll say 'handles behind `global_exprs_iter`' to
68
+ // mean handles that have already been produced by
69
+ // `global_exprs_iter`. Once `global_exprs_iter` returns `None`, all
70
+ // global expression handles are 'behind' it.
71
+ //
72
+ // At this point:
73
+ //
74
+ // - All types visited by prior iterations (that is, before
75
+ // `th`/`t`) refer only to expressions behind `global_exprs_iter`.
76
+ //
77
+ // On the first iteration, this is obviously true: there are no
78
+ // prior iterations, and `global_exprs_iter` hasn't produced
79
+ // anything yet. At the bottom of the loop, we'll claim that it's
80
+ // true for `th`/`t` as well, so the condition remains true when
81
+ // we advance to the next type.
82
+ //
83
+ // - All expressions behind `global_exprs_iter` refer only to
84
+ // previously visited types.
85
+ //
86
+ // Again, trivially true at the start, and we'll show it's true
87
+ // about each expression that `global_exprs_iter` produces.
88
+ //
89
+ // Once we also check that arena elements only refer to prior
90
+ // elements in that arena, we can see that `th`/`t` does not
91
+ // participate in a cycle: it only refers to previously visited
92
+ // types and expressions behind `global_exprs_iter`, and none of
93
+ // those refer to `th`/`t`, because they passed the same checks
94
+ // before we reached `th`/`t`.
95
+ if let Some ( max_expr) = Self :: validate_type_handles ( ( th, t) ) ? {
96
+ max_expr. check_valid_for ( global_expressions) ?;
97
+ // Since `t` refers to `max_expr`, if we want our invariants to
98
+ // remain true, we must advance `global_exprs_iter` beyond
99
+ // `max_expr`.
100
+ while let Some ( ( eh, e) ) = global_exprs_iter. next_if ( |& ( eh, _) | eh <= max_expr) {
101
+ if let Some ( max_type) =
102
+ Self :: validate_const_expression_handles ( ( eh, e) , constants, overrides) ?
103
+ {
104
+ // Show that `eh` refers only to previously visited types.
105
+ th. check_dep ( max_type) ?;
106
+ }
107
+ // We've advanced `global_exprs_iter` past `eh` already. But
108
+ // since we now know that `eh` refers only to previously
109
+ // visited types, it is again true that all expressions
110
+ // behind `global_exprs_iter` refer only to previously
111
+ // visited types. So we can continue to the next expression.
71
112
}
72
113
}
114
+
115
+ // Here we know that if `th` refers to any expressions at all,
116
+ // `max_expr` is the latest one. And we know that `max_expr` is
117
+ // behind `global_exprs_iter`. So `th` refers only to expressions
118
+ // behind `global_exprs_iter`, and the invariants will still be
119
+ // true on the next iteration.
73
120
}
74
121
75
- for handle_and_expr in global_expressions. iter ( ) {
76
- Self :: validate_const_expression_handles ( handle_and_expr, constants, overrides, types) ?;
122
+ // Since we also enforced the usual intra-arena rules that expressions
123
+ // refer only to prior expressions, expressions can only form cycles if
124
+ // they include types. But we've shown that all types are acyclic, so
125
+ // all expressions must be acyclic as well.
126
+ //
127
+ // Validate the remaining expressions normally.
128
+ for handle_and_expr in global_exprs_iter {
129
+ Self :: validate_const_expression_handles ( handle_and_expr, constants, overrides) ?;
77
130
}
78
131
79
132
let validate_type = |handle| Self :: validate_type_handle ( handle, types) ;
@@ -239,38 +292,86 @@ impl super::Validator {
239
292
handle. check_valid_for ( functions) . map ( |_| ( ) )
240
293
}
241
294
295
+ /// Validate all handles that occur in `ty`, whose handle is `handle`.
296
+ ///
297
+ /// If `ty` refers to any expressions, return the highest-indexed expression
298
+ /// handle that it uses. This is used for detecting cycles between the
299
+ /// expression and type arenas.
300
+ fn validate_type_handles (
301
+ ( handle, ty) : ( Handle < crate :: Type > , & crate :: Type ) ,
302
+ ) -> Result < Option < Handle < crate :: Expression > > , InvalidHandleError > {
303
+ let max_expr = match ty. inner {
304
+ crate :: TypeInner :: Scalar { .. }
305
+ | crate :: TypeInner :: Vector { .. }
306
+ | crate :: TypeInner :: Matrix { .. }
307
+ | crate :: TypeInner :: ValuePointer { .. }
308
+ | crate :: TypeInner :: Atomic { .. }
309
+ | crate :: TypeInner :: Image { .. }
310
+ | crate :: TypeInner :: Sampler { .. }
311
+ | crate :: TypeInner :: AccelerationStructure
312
+ | crate :: TypeInner :: RayQuery => None ,
313
+ crate :: TypeInner :: Pointer { base, space : _ } => {
314
+ handle. check_dep ( base) ?;
315
+ None
316
+ }
317
+ crate :: TypeInner :: Array { base, size, .. }
318
+ | crate :: TypeInner :: BindingArray { base, size, .. } => {
319
+ handle. check_dep ( base) ?;
320
+ match size {
321
+ crate :: ArraySize :: Pending ( pending) => match pending {
322
+ crate :: PendingArraySize :: Expression ( expr) => Some ( expr) ,
323
+ crate :: PendingArraySize :: Override ( _) => None ,
324
+ } ,
325
+ crate :: ArraySize :: Constant ( _) | crate :: ArraySize :: Dynamic => None ,
326
+ }
327
+ }
328
+ crate :: TypeInner :: Struct {
329
+ ref members,
330
+ span : _,
331
+ } => {
332
+ handle. check_dep_iter ( members. iter ( ) . map ( |m| m. ty ) ) ?;
333
+ None
334
+ }
335
+ } ;
336
+
337
+ Ok ( max_expr)
338
+ }
339
+
340
+ /// Validate all handles that occur in `expression`, whose handle is `handle`.
341
+ ///
342
+ /// If `expression` refers to any `Type`s, return the highest-indexed type
343
+ /// handle that it uses. This is used for detecting cycles between the
344
+ /// expression and type arenas.
242
345
fn validate_const_expression_handles (
243
346
( handle, expression) : ( Handle < crate :: Expression > , & crate :: Expression ) ,
244
347
constants : & Arena < crate :: Constant > ,
245
348
overrides : & Arena < crate :: Override > ,
246
- types : & UniqueArena < crate :: Type > ,
247
- ) -> Result < ( ) , InvalidHandleError > {
349
+ ) -> Result < Option < Handle < crate :: Type > > , InvalidHandleError > {
248
350
let validate_constant = |handle| Self :: validate_constant_handle ( handle, constants) ;
249
351
let validate_override = |handle| Self :: validate_override_handle ( handle, overrides) ;
250
- let validate_type = |handle| Self :: validate_type_handle ( handle, types) ;
251
352
252
- match * expression {
253
- crate :: Expression :: Literal ( _) => { }
353
+ let max_type = match * expression {
354
+ crate :: Expression :: Literal ( _) => None ,
254
355
crate :: Expression :: Constant ( constant) => {
255
356
validate_constant ( constant) ?;
256
357
handle. check_dep ( constants[ constant] . init ) ?;
358
+ None
257
359
}
258
360
crate :: Expression :: Override ( override_) => {
259
361
validate_override ( override_) ?;
260
362
if let Some ( init) = overrides[ override_] . init {
261
363
handle. check_dep ( init) ?;
262
364
}
365
+ None
263
366
}
264
- crate :: Expression :: ZeroValue ( ty) => {
265
- validate_type ( ty) ?;
266
- }
367
+ crate :: Expression :: ZeroValue ( ty) => Some ( ty) ,
267
368
crate :: Expression :: Compose { ty, ref components } => {
268
- validate_type ( ty) ?;
269
369
handle. check_dep_iter ( components. iter ( ) . copied ( ) ) ?;
370
+ Some ( ty)
270
371
}
271
- _ => { }
272
- }
273
- Ok ( ( ) )
372
+ _ => None ,
373
+ } ;
374
+ Ok ( max_type )
274
375
}
275
376
276
377
#[ allow( clippy:: too_many_arguments) ]
@@ -783,8 +884,47 @@ fn constant_deps() {
783
884
handle_and_expr,
784
885
& constants,
785
886
& overrides,
786
- & types,
787
887
)
788
888
. is_err( ) ) ;
789
889
}
790
890
}
891
+
892
+ #[ test]
893
+ fn override_deps ( ) {
894
+ use super :: Validator ;
895
+ use crate :: { ArraySize , Expression , PendingArraySize , Scalar , Span , Type , TypeInner } ;
896
+
897
+ let nowhere = Span :: default ( ) ;
898
+
899
+ let mut m = crate :: Module :: default ( ) ;
900
+
901
+ let ty_u32 = m. types . insert (
902
+ Type {
903
+ name : Some ( "u32" . to_string ( ) ) ,
904
+ inner : TypeInner :: Scalar ( Scalar :: U32 ) ,
905
+ } ,
906
+ nowhere,
907
+ ) ;
908
+ let ex_zero = m
909
+ . global_expressions
910
+ . append ( Expression :: ZeroValue ( ty_u32) , nowhere) ;
911
+ let ty_arr = m. types . insert (
912
+ Type {
913
+ name : Some ( "bad_array" . to_string ( ) ) ,
914
+ inner : TypeInner :: Array {
915
+ base : ty_u32,
916
+ size : ArraySize :: Pending ( PendingArraySize :: Expression ( ex_zero) ) ,
917
+ stride : 4 ,
918
+ } ,
919
+ } ,
920
+ nowhere,
921
+ ) ;
922
+
923
+ // Everything should be okay now.
924
+ assert ! ( Validator :: validate_module_handles( & m) . is_ok( ) ) ;
925
+
926
+ // Mutate `ex_zero`'s type to `ty_arr`, introducing a cycle.
927
+ // Validation should catch the cycle.
928
+ m. global_expressions [ ex_zero] = Expression :: ZeroValue ( ty_arr) ;
929
+ assert ! ( Validator :: validate_module_handles( & m) . is_err( ) ) ;
930
+ }
0 commit comments