Skip to content

Commit d8cb680

Browse files
committed
fix(naga): Improve validation of non-constructible types
Fixes #4720 Fixes the test cases in #7393, but not the issue itself
1 parent b042784 commit d8cb680

10 files changed

Lines changed: 585 additions & 95 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Bottom level categories:
7171
- Reject splat vector construction if the argument type does not match the type of the vector's scalar. Previously it would succeed. By @mooori in [#8829](https://github.com/gfx-rs/wgpu/pull/8829).
7272
- Fixed `workgroupUniformLoad` incorrectly returning an atomic when called on an atomic, it now returns the inner `T` as per the spec. By @cryvosh in [#8791](https://github.com/gfx-rs/wgpu/pull/8791).
7373
- Fixed constant evaluation for `sign()` builtin to return zero when the argument is zero. By @mandryskowski in [#8942](https://github.com/gfx-rs/wgpu/pull/8942).
74+
- Reject non-constructible types (runtime- and override-sized arrays, and structs containing non-constructible types) in more places where they should not be allowed. By @andyleiserson in [#8873](https://github.com/gfx-rs/wgpu/pull/8873).
7475

7576
#### GLES
7677

@@ -107,7 +108,7 @@ This has been a long time coming. See [the tracking issue](https://github.com/gf
107108
They are now fully supported on Vulkan, and supported on Metal and DX12 with passthrough shaders. WGSL parsing and rewriting
108109
is supported, meaning they can be used through WESL or naga_oil.
109110

110-
Mesh shader pipelines replace the standard vertex shader pipelines and allow new ways to render meshes.
111+
Mesh shader pipelines replace the standard vertex shader pipelines and allow new ways to render meshes.
111112
They are ideal for meshlet rendering, a form of rendering where small groups of triangles are handled together,
112113
for both culling and rendering.
113114

@@ -154,7 +155,7 @@ fn ms_main(@builtin(local_invocation_index) index: u32, @builtin(global_invocati
154155
155156
mesh_output.vertices[2].position = positions[2];
156157
mesh_output.vertices[2].color = colors[2] * taskPayload.colorMask;
157-
158+
158159
// Set the vertex indices for the only primitive
159160
mesh_output.primitives[0].indices = vec3<u32>(0, 1, 2);
160161
// Cull it if the data passed by the task shader says to

cts_runner/test.lst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,17 @@ webgpu:shader,validation,expression,call,builtin,all:arguments:test="ptr_deref"
224224
webgpu:shader,validation,expression,call,builtin,distance:values:stage="constant";type="f32"
225225
webgpu:shader,validation,expression,call,builtin,length:scalar:stage="constant";type="f32"
226226
webgpu:shader,validation,expression,call,builtin,max:values:*
227-
// FAIL: others in `value_constructor` due to https://github.com/gfx-rs/wgpu/issues/4720, possibly more
228227
webgpu:shader,validation,expression,call,builtin,value_constructor:array_value:*
228+
webgpu:shader,validation,expression,call,builtin,value_constructor:array_zero_value:*
229229
webgpu:shader,validation,expression,call,builtin,value_constructor:matrix_zero_value:*
230+
webgpu:shader,validation,expression,call,builtin,value_constructor:partial_eval:*
230231
webgpu:shader,validation,expression,call,builtin,value_constructor:scalar_value:*
231232
webgpu:shader,validation,expression,call,builtin,value_constructor:scalar_zero_value:*
232233
webgpu:shader,validation,expression,call,builtin,value_constructor:struct_value:*
234+
webgpu:shader,validation,expression,call,builtin,value_constructor:struct_zero_value:*
235+
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_copy:*
236+
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_elementwise:*
237+
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_mixed:*
233238
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_splat:*
234239
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_zero_value:*
235240
// NOTE: This is supposed to be an exhaustive listing underneath

naga/src/front/wgsl/lower/construction.rs

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -164,33 +164,38 @@ impl<'source> Lowerer<'source, '_> {
164164

165165
let expr;
166166
match (components, constructor) {
167-
// Empty constructor
168-
(Components::None, dst_ty) => match dst_ty {
169-
Constructor::Type((result_ty, _)) => {
170-
expr = crate::Expression::ZeroValue(result_ty);
171-
}
172-
Constructor::PartialVector { size } => {
173-
// vec2(), vec3(), vec4() return vectors of abstractInts; the same
174-
// is not true of the similar constructors for matrices or arrays.
175-
// See https://www.w3.org/TR/WGSL/#vec2-builtin et seq.
176-
let result_ty = ctx.module.types.insert(
177-
crate::Type {
178-
name: None,
179-
inner: crate::TypeInner::Vector {
180-
size,
181-
scalar: crate::Scalar::ABSTRACT_INT,
182-
},
167+
// Zero-value constructor with explicit type. Not everything this
168+
// matches is constructible, but the non-constructible types not
169+
// excluded by `!is_dynamically_sized` are rejected by the
170+
// parser.
171+
(Components::None, Constructor::Type((result_ty, inner)))
172+
if !inner.is_dynamically_sized(&ctx.module.types) =>
173+
{
174+
expr = crate::Expression::ZeroValue(result_ty);
175+
}
176+
// Zero-value constructor, vector with type inference
177+
(Components::None, Constructor::PartialVector { size }) => {
178+
// vec2(), vec3(), vec4() return vectors of abstractInts; the same
179+
// is not true of the similar constructors for matrices or arrays.
180+
// See https://www.w3.org/TR/WGSL/#vec2-builtin et seq.
181+
let result_ty = ctx.module.types.insert(
182+
crate::Type {
183+
name: None,
184+
inner: crate::TypeInner::Vector {
185+
size,
186+
scalar: crate::Scalar::ABSTRACT_INT,
183187
},
184-
span,
185-
);
186-
expr = crate::Expression::ZeroValue(result_ty);
187-
}
188-
Constructor::PartialMatrix { .. } | Constructor::PartialArray => {
189-
// We have no arguments from which to infer the result type, so
190-
// partial constructors aren't acceptable here.
191-
return Err(Box::new(Error::TypeNotInferable(ty_span)));
192-
}
193-
},
188+
},
189+
span,
190+
);
191+
expr = crate::Expression::ZeroValue(result_ty);
192+
}
193+
// Zero-value constructor, matrix or array with type inference
194+
(Components::None, Constructor::PartialMatrix { .. } | Constructor::PartialArray) => {
195+
// We have no arguments from which to infer the result type, so
196+
// partial constructors aren't acceptable here.
197+
return Err(Box::new(Error::TypeNotInferable(ty_span)));
198+
}
194199

195200
// Scalar constructor & conversion (scalar -> scalar)
196201
(
@@ -539,8 +544,11 @@ impl<'source> Lowerer<'source, '_> {
539544
expr = crate::Expression::Compose { ty, components };
540545
}
541546

542-
// Array constructor, explicit type
543-
(components, Constructor::Type((ty, &crate::TypeInner::Array { base, .. }))) => {
547+
// Array constructor, explicit type. Override- and runtime-sized arrays are not constructible.
548+
(
549+
components,
550+
Constructor::Type((ty, inner @ &crate::TypeInner::Array { base, .. })),
551+
) if !inner.is_dynamically_sized(&ctx.module.types) => {
544552
let mut components = components.into_components_vec();
545553
ctx.try_automatic_conversions_slice(&mut components, &Tr::Handle(base), ty_span)?;
546554
expr = crate::Expression::Compose { ty, components };
@@ -549,8 +557,8 @@ impl<'source> Lowerer<'source, '_> {
549557
// Struct constructor
550558
(
551559
components,
552-
Constructor::Type((ty, &crate::TypeInner::Struct { ref members, .. })),
553-
) => {
560+
Constructor::Type((ty, inner @ &crate::TypeInner::Struct { ref members, .. })),
561+
) if !inner.is_dynamically_sized(&ctx.module.types) => {
554562
let mut components = components.into_components_vec();
555563
let struct_ty_span = ctx.module.types.get_span(ty);
556564

naga/src/front/wgsl/lower/mod.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1717,14 +1717,28 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
17171717

17181718
let mut ectx = ctx.as_expression(block, &mut emitter);
17191719

1720-
let (_ty, initializer) = self.type_and_init(
1720+
let (ty, initializer) = self.type_and_init(
17211721
l.name,
17221722
Some(l.init),
17231723
explicit_ty,
17241724
AbstractRule::Concretize,
17251725
&mut ectx,
17261726
)?;
17271727

1728+
// We have this special check here for `let` declarations because the
1729+
// validator doesn't check them (they are comingled with other things in
1730+
// `named_expressions`; see <https://github.com/gfx-rs/wgpu/issues/7393>).
1731+
// The check could go in `type_and_init`, but then we'd have to
1732+
// distinguish whether override-sized is allowed. The error ought to use
1733+
// the type's span, but `module.types.get_span(ty)` is `Span::UNDEFINED`
1734+
// (see <https://github.com/gfx-rs/wgpu/issues/7951>).
1735+
if ctx.module.types[ty]
1736+
.inner
1737+
.is_dynamically_sized(&ctx.module.types)
1738+
{
1739+
return Err(Box::new(Error::TypeNotConstructible(l.name.span)));
1740+
}
1741+
17281742
// We passed `Some()` to `type_and_init`, so we
17291743
// will get a lowered initializer expression back.
17301744
let initializer =

naga/src/proc/type_methods.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,18 @@ impl crate::TypeInner {
344344
left.as_ref().unwrap_or(self) == right.as_ref().unwrap_or(rhs)
345345
}
346346

347+
/// Returns true if `self` is runtime- or override-sized.
347348
pub fn is_dynamically_sized(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
348349
use crate::TypeInner as Ti;
349350
match *self {
350-
Ti::Array { size, .. } => size == crate::ArraySize::Dynamic,
351+
Ti::Array {
352+
size: crate::ArraySize::Constant(_),
353+
..
354+
} => false,
355+
Ti::Array {
356+
size: crate::ArraySize::Pending(_) | crate::ArraySize::Dynamic,
357+
..
358+
} => true,
351359
Ti::Struct { ref members, .. } => members
352360
.last()
353361
.map(|last| types[last.ty].inner.is_dynamically_sized(types))

naga/src/valid/expression.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
use super::{compose::validate_compose, FunctionInfo, ModuleInfo, ShaderStages, TypeFlags};
22
use crate::arena::UniqueArena;
3-
use crate::valid::expression::builtin::validate_zero_value;
43
use crate::{
54
arena::Handle,
65
proc::OverloadSet as _,
76
proc::{IndexableLengthError, ResolveError},
87
};
98

10-
pub mod builtin;
11-
129
#[derive(Clone, Debug, thiserror::Error)]
1310
#[cfg_attr(test, derive(PartialEq))]
1411
pub enum ExpressionError {
@@ -38,8 +35,8 @@ pub enum ExpressionError {
3835
InvalidSwizzleComponent(crate::SwizzleComponent, crate::VectorSize),
3936
#[error(transparent)]
4037
Compose(#[from] super::ComposeError),
41-
#[error(transparent)]
42-
ZeroValue(#[from] super::ZeroValueError),
38+
#[error("Cannot construct zero value of {0:?} because it is not a constructible type")]
39+
InvalidZeroValue(Handle<crate::Type>),
4340
#[error(transparent)]
4441
IndexableLength(#[from] IndexableLengthError),
4542
#[error("Operation {0:?} can't work with {1:?}")]
@@ -387,7 +384,9 @@ impl super::Validator {
387384
}
388385
E::Constant(_) | E::Override(_) => ShaderStages::all(),
389386
E::ZeroValue(ty) => {
390-
validate_zero_value(ty, module.to_ctx())?;
387+
if !mod_info[ty].contains(TypeFlags::CONSTRUCTIBLE) {
388+
return Err(ExpressionError::InvalidZeroValue(ty));
389+
}
391390
ShaderStages::all()
392391
}
393392
E::Compose { ref components, ty } => {

naga/src/valid/expression/builtin.rs

Lines changed: 0 additions & 26 deletions
This file was deleted.

naga/src/valid/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use crate::{
2727
use crate::span::{AddSpan as _, WithSpan};
2828
pub use analyzer::{ExpressionInfo, FunctionInfo, GlobalUse, Uniformity, UniformityRequirements};
2929
pub use compose::ComposeError;
30-
pub use expression::builtin::ZeroValueError;
3130
pub use expression::{check_literal_value, LiteralError};
3231
pub use expression::{ConstExpressionError, ExpressionError};
3332
pub use function::{CallError, FunctionError, LocalVariableError, SubgroupError};

0 commit comments

Comments
 (0)