mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[spv-out]: Ensure array subscripts are in bounds.
This commit is contained in:
committed by
Dzmitry Malyshau
parent
a7cacab276
commit
c16f2097ad
@@ -1,7 +1,7 @@
|
||||
use super::{compose::validate_compose, ComposeError, FunctionInfo, ShaderStages, TypeFlags};
|
||||
use crate::{
|
||||
arena::{Arena, Handle},
|
||||
proc::ResolveError,
|
||||
proc::{ProcError, ResolveError},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
@@ -17,8 +17,8 @@ pub enum ExpressionError {
|
||||
InvalidBaseType(Handle<crate::Expression>),
|
||||
#[error("Accessing with index {0:?} can't be done")]
|
||||
InvalidIndexType(Handle<crate::Expression>),
|
||||
#[error("Accessing index {1} is out of {0:?} bounds")]
|
||||
IndexOutOfBounds(Handle<crate::Expression>, u32),
|
||||
#[error("Accessing index {1:?} is out of {0:?} bounds")]
|
||||
IndexOutOfBounds(Handle<crate::Expression>, crate::ScalarValue),
|
||||
#[error("The expression {0:?} may only be indexed by a constant")]
|
||||
IndexMustBeConstant(Handle<crate::Expression>),
|
||||
#[error("Function argument {0:?} doesn't exist")]
|
||||
@@ -41,6 +41,8 @@ pub enum ExpressionError {
|
||||
InvalidSwizzleComponent(crate::SwizzleComponent, crate::VectorSize),
|
||||
#[error(transparent)]
|
||||
Compose(#[from] ComposeError),
|
||||
#[error(transparent)]
|
||||
Proc(#[from] ProcError),
|
||||
#[error("Operation {0:?} can't work with {1:?}")]
|
||||
InvalidUnaryOperandType(crate::UnaryOperator, Handle<crate::Expression>),
|
||||
#[error("Operation {0:?} can't work with {1:?} and {2:?}")]
|
||||
@@ -144,8 +146,9 @@ impl super::Validator {
|
||||
|
||||
let stages = match *expression {
|
||||
E::Access { base, index } => {
|
||||
let base_type = resolver.resolve(base)?;
|
||||
// See the documentation for `Expression::Access`.
|
||||
let dynamic_indexing_restricted = match *resolver.resolve(base)? {
|
||||
let dynamic_indexing_restricted = match *base_type {
|
||||
Ti::Vector { .. } => false,
|
||||
Ti::Matrix { .. } | Ti::Array { .. } => true,
|
||||
Ti::Pointer { .. } | Ti::ValuePointer { size: Some(_), .. } => false,
|
||||
@@ -174,6 +177,36 @@ impl super::Validator {
|
||||
{
|
||||
return Err(ExpressionError::IndexMustBeConstant(base));
|
||||
}
|
||||
|
||||
// If we know both the length and the index, we can do the
|
||||
// bounds check now.
|
||||
if let crate::proc::IndexableLength::Known(known_length) =
|
||||
base_type.indexable_length(module)?
|
||||
{
|
||||
if let E::Constant(k) = function.expressions[index] {
|
||||
if let crate::Constant {
|
||||
// We must treat specializable constants as unknown.
|
||||
specialization: None,
|
||||
// Non-scalar indices should have been caught above.
|
||||
inner: crate::ConstantInner::Scalar { value, .. },
|
||||
..
|
||||
} = module.constants[k]
|
||||
{
|
||||
match value {
|
||||
crate::ScalarValue::Uint(u) if u >= known_length as u64 => {
|
||||
return Err(ExpressionError::IndexOutOfBounds(base, value));
|
||||
}
|
||||
crate::ScalarValue::Sint(s)
|
||||
if s < 0 || s >= known_length as i64 =>
|
||||
{
|
||||
return Err(ExpressionError::IndexOutOfBounds(base, value));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderStages::all()
|
||||
}
|
||||
E::AccessIndex { base, index } => {
|
||||
@@ -208,7 +241,10 @@ impl super::Validator {
|
||||
|
||||
let limit = resolve_index_limit(module, base, resolver.resolve(base)?, true)?;
|
||||
if index >= limit {
|
||||
return Err(ExpressionError::IndexOutOfBounds(base, index));
|
||||
return Err(ExpressionError::IndexOutOfBounds(
|
||||
base,
|
||||
crate::ScalarValue::Uint(limit as _),
|
||||
));
|
||||
}
|
||||
ShaderStages::all()
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ pub enum TypeError {
|
||||
InvalidArrayBaseType(Handle<crate::Type>),
|
||||
#[error("The constant {0:?} can not be used for an array size")]
|
||||
InvalidArraySizeConstant(Handle<crate::Constant>),
|
||||
#[error("Array type {0:?} must have a length of one or more")]
|
||||
NonPositiveArrayLength(Handle<crate::Constant>),
|
||||
#[error("Array stride {stride} is smaller than the base element size {base_size}")]
|
||||
InsufficientArrayStride { stride: u32, base_size: u32 },
|
||||
#[error("Field '{0}' can't be dynamically-sized, has type {1:?}")]
|
||||
@@ -288,15 +290,15 @@ impl super::Validator {
|
||||
|
||||
let sized_flag = match size {
|
||||
crate::ArraySize::Constant(const_handle) => {
|
||||
match constants.try_get(const_handle) {
|
||||
let length_is_positive = match constants.try_get(const_handle) {
|
||||
Some(&crate::Constant {
|
||||
inner:
|
||||
crate::ConstantInner::Scalar {
|
||||
width: _,
|
||||
value: crate::ScalarValue::Uint(_),
|
||||
value: crate::ScalarValue::Uint(length),
|
||||
},
|
||||
..
|
||||
}) => {}
|
||||
}) => length > 0,
|
||||
// Accept a signed integer size to avoid
|
||||
// requiring an explicit uint
|
||||
// literal. Type inference should make
|
||||
@@ -305,14 +307,18 @@ impl super::Validator {
|
||||
inner:
|
||||
crate::ConstantInner::Scalar {
|
||||
width: _,
|
||||
value: crate::ScalarValue::Sint(_),
|
||||
value: crate::ScalarValue::Sint(length),
|
||||
},
|
||||
..
|
||||
}) => {}
|
||||
}) => length > 0,
|
||||
other => {
|
||||
log::warn!("Array size {:?}", other);
|
||||
return Err(TypeError::InvalidArraySizeConstant(const_handle));
|
||||
}
|
||||
};
|
||||
|
||||
if !length_is_positive {
|
||||
return Err(TypeError::NonPositiveArrayLength(const_handle));
|
||||
}
|
||||
|
||||
TypeFlags::SIZED
|
||||
|
||||
Reference in New Issue
Block a user