diff --git a/CHANGELOG.md b/CHANGELOG.md index c7bf265f77..e3a0b25ee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,10 @@ Bottom level categories: - `DisplayHandle` should now be passed to `InstanceDescriptor` for correct EGL initialization on Wayland. By @MarijnS95 in [#8012](https://github.com/gfx-rs/wgpu/pull/8012) Note that the existing workaround to create surfaces before the adapter is no longer valid. +#### naga + +- Reject zero-value construction of a runtime-sized array with a validation error. Previously it would crash in the HLSL backend. By @mooori in [#8741](https://github.com/gfx-rs/wgpu/pull/8741). + ### Documentation #### General diff --git a/naga/src/valid/expression.rs b/naga/src/valid/expression.rs index 13ebb8461b..bf5a265c11 100644 --- a/naga/src/valid/expression.rs +++ b/naga/src/valid/expression.rs @@ -1,11 +1,14 @@ use super::{compose::validate_compose, FunctionInfo, ModuleInfo, ShaderStages, TypeFlags}; use crate::arena::UniqueArena; +use crate::valid::expression::builtin::validate_zero_value; use crate::{ arena::Handle, proc::OverloadSet as _, proc::{IndexableLengthError, ResolveError}, }; +pub mod builtin; + #[derive(Clone, Debug, thiserror::Error)] #[cfg_attr(test, derive(PartialEq))] pub enum ExpressionError { @@ -36,6 +39,8 @@ pub enum ExpressionError { #[error(transparent)] Compose(#[from] super::ComposeError), #[error(transparent)] + ZeroValue(#[from] super::ZeroValueError), + #[error(transparent)] IndexableLength(#[from] IndexableLengthError), #[error("Operation {0:?} can't work with {1:?}")] InvalidUnaryOperandType(crate::UnaryOperator, Handle), @@ -377,7 +382,11 @@ impl super::Validator { self.validate_literal(literal)?; ShaderStages::all() } - E::Constant(_) | E::Override(_) | E::ZeroValue(_) => ShaderStages::all(), + E::Constant(_) | E::Override(_) => ShaderStages::all(), + E::ZeroValue(ty) => { + validate_zero_value(ty, module.to_ctx())?; + ShaderStages::all() + } E::Compose { ref components, ty } => { validate_compose( ty, diff --git a/naga/src/valid/expression/builtin.rs b/naga/src/valid/expression/builtin.rs new file mode 100644 index 0000000000..d570bbccd0 --- /dev/null +++ b/naga/src/valid/expression/builtin.rs @@ -0,0 +1,26 @@ +use crate::arena::Handle; + +#[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] +pub enum ZeroValueError { + #[error("ZeroValue construction of runtime-sized array is not allowed")] + RuntimeSizedArray, +} + +pub fn validate_zero_value( + self_ty_handle: Handle, + gctx: crate::proc::GlobalCtx, +) -> Result<(), ZeroValueError> { + use crate::TypeInner as Ti; + match gctx.types[self_ty_handle].inner { + Ti::Array { + base: _, + size: crate::ArraySize::Dynamic, + stride: _, + } => { + log::error!("Constructing zero value of runtime-sized array"); + Err(ZeroValueError::RuntimeSizedArray) + } + _ => Ok(()), + } +} diff --git a/naga/src/valid/mod.rs b/naga/src/valid/mod.rs index 8bfc215014..984a47262b 100644 --- a/naga/src/valid/mod.rs +++ b/naga/src/valid/mod.rs @@ -27,6 +27,7 @@ use crate::{ use crate::span::{AddSpan as _, WithSpan}; pub use analyzer::{ExpressionInfo, FunctionInfo, GlobalUse, Uniformity, UniformityRequirements}; pub use compose::ComposeError; +pub use expression::builtin::ZeroValueError; pub use expression::{check_literal_value, LiteralError}; pub use expression::{ConstExpressionError, ExpressionError}; pub use function::{CallError, FunctionError, LocalVariableError, SubgroupError}; diff --git a/naga/tests/naga/validation.rs b/naga/tests/naga/validation.rs index 78d5ff19f7..789c3a1ec2 100644 --- a/naga/tests/naga/validation.rs +++ b/naga/tests/naga/validation.rs @@ -727,6 +727,35 @@ fn bad_texture_dimensions_level() { assert!(validate("1").is_ok()); } +#[test] +fn zero_value_dyn_array_error() { + let source = r#" + @compute @workgroup_size(1) + fn main() { + let a = array(); + } + "#; + let module = naga::front::wgsl::parse_str(source).expect("module should parse"); + let err = valid::Validator::new(Default::default(), valid::Capabilities::all()) + .validate(&module) + .map_err(|err| err.into_inner()); // discard spans + assert!(matches!( + err, + Err(naga::valid::ValidationError::EntryPoint { + stage: _, + name: _, + source: naga::valid::EntryPointError::Function( + naga::valid::FunctionError::Expression { + handle: _, + source: naga::valid::ExpressionError::ZeroValue( + naga::valid::ZeroValueError::RuntimeSizedArray + ) + } + ) + }) + )); +} + #[test] fn arity_check() { use ir::MathFunction as Mf;