From 2db49b6998a6159552a2bcb4395fae1664332e60 Mon Sep 17 00:00:00 2001 From: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> Date: Sun, 10 Apr 2022 07:35:28 +0200 Subject: [PATCH] validate uniform address space layout constraints (#1812) --- src/valid/type.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/valid/type.rs b/src/valid/type.rs index aae4fbd11b..6eaa689d64 100644 --- a/src/valid/type.rs +++ b/src/valid/type.rs @@ -4,6 +4,8 @@ use crate::{ proc::Alignment, }; +const UNIFORM_MIN_ALIGNMENT: Alignment = unsafe { Alignment::new_unchecked(16) }; + bitflags::bitflags! { /// Flags associated with [`Type`]s by [`Validator`]. /// @@ -64,6 +66,12 @@ pub enum Disalignment { offset: u32, alignment: u32, }, + #[error("The struct member[{index}] offset {offset} must be at least {expected}")] + MemberOffsetAfterStruct { + index: u32, + offset: u32, + expected: u32, + }, #[error("The struct member[{index}] is not statically sized")] UnsizedMember { index: u32 }, #[error("The type is not host-shareable")] @@ -341,7 +349,11 @@ impl super::Validator { let uniform_layout = match base_info.uniform_layout { Ok(base_alignment) => { // combine the alignment requirements - let align = base_alignment.unwrap().get().max(general_alignment); + let align = base_alignment + .unwrap() + .get() + .max(general_alignment) + .max(UNIFORM_MIN_ALIGNMENT.get()); if stride % align != 0 { Err(( handle, @@ -448,8 +460,12 @@ impl super::Validator { | TypeFlags::ARGUMENT, 1, ); + ti.uniform_layout = Ok(Some(UNIFORM_MIN_ALIGNMENT)); + let mut min_offset = 0; + let mut prev_struct_data: Option<(u32, u32)> = None; + for (i, member) in members.iter().enumerate() { if member.ty >= handle { return Err(TypeError::UnresolvedBase(member.ty)); @@ -509,6 +525,29 @@ impl super::Validator { handle, ); + // Validate rule: If a structure member itself has a structure type S, + // then the number of bytes between the start of that member and + // the start of any following member must be at least roundUp(16, SizeOf(S)). + if let Some((span, offset)) = prev_struct_data { + let diff = member.offset - offset; + let min = crate::valid::Layouter::round_up(UNIFORM_MIN_ALIGNMENT, span); + if diff < min { + ti.uniform_layout = Err(( + handle, + Disalignment::MemberOffsetAfterStruct { + index: i as u32, + offset: member.offset, + expected: offset + min, + }, + )); + } + }; + + prev_struct_data = match types[member.ty].inner { + crate::TypeInner::Struct { span, .. } => Some((span, member.offset)), + _ => None, + }; + // The last field may be an unsized array. if !base_info.flags.contains(TypeFlags::SIZED) { let is_array = match types[member.ty].inner {