From 5827b1cba4f8da4de392f84ade52ef673c89bbaf Mon Sep 17 00:00:00 2001 From: Tim Balsfulland Date: Wed, 24 Jul 2024 13:26:59 +0200 Subject: [PATCH] check the validity of builder structs The only thing that isn't checked is that the `space` and `swapchain` handles come from the same session. The spec only mentions this for the cube layer, but it is probably required for all layers. --- generator/src/main.rs | 8 ++- openxr/src/action.rs | 24 +++++++++ openxr/src/frame_stream.rs | 99 ++++++++++++++++++++++++++++++++++++-- openxr/src/generated.rs | 16 +++++- 4 files changed, 141 insertions(+), 6 deletions(-) diff --git a/generator/src/main.rs b/generator/src/main.rs index 662a8e4d..fd70f95a 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -1758,9 +1758,15 @@ impl Parser { quote! { #[repr(transparent)] pub struct #base_ident #type_params { - _inner: sys::#sys_ident, + inner: sys::#sys_ident, #marker } + impl #type_params #base_ident #type_args { + #[inline] + pub(crate) fn as_raw(&self) -> &sys::#sys_ident { + &self.inner + } + } #(#builders)* } } diff --git a/openxr/src/action.rs b/openxr/src/action.rs index 8699556e..383b4f16 100644 --- a/openxr/src/action.rs +++ b/openxr/src/action.rs @@ -128,6 +128,8 @@ impl Action { subaction_path: Path, event: &HapticBase, ) -> Result<()> { + self.assert_event_validity(event); + let info = sys::HapticActionInfo { ty: sys::HapticActionInfo::TYPE, next: ptr::null(), @@ -144,6 +146,28 @@ impl Action { Ok(()) } + /// Check the invariants of the passed haptic `event`. + /// The lifetime guarantees the validity of the non-null pointers. + fn assert_event_validity(&self, event: &HapticBase) { + match event.as_raw().ty { + sys::HapticVibration::TYPE => { + // nothing to check + } + sys::HapticPcmVibrationFB::TYPE => { + assert!(self.instance().exts().fb_haptic_pcm.is_some()); + let event = + unsafe { std::mem::transmute::<&HapticBase, &HapticPcmVibrationFB>(event) } + .as_raw(); + assert!(event.buffer_size > 0); + assert_ne!(event.buffer, ptr::null()); + assert_ne!(event.samples_consumed, ptr::null_mut()); + } + ty => { + panic!("unsupported haptic type: {:?}", ty) + } + } + } + pub fn stop_feedback(&self, session: &Session, subaction_path: Path) -> Result<()> { let info = sys::HapticActionInfo { ty: sys::HapticActionInfo::TYPE, diff --git a/openxr/src/frame_stream.rs b/openxr/src/frame_stream.rs index f1a841b3..cdf83dbb 100644 --- a/openxr/src/frame_stream.rs +++ b/openxr/src/frame_stream.rs @@ -107,7 +107,7 @@ impl FrameStream { environment_blend_mode: EnvironmentBlendMode, layers: &[&CompositionLayerBase<'_, G>], ) -> Result<()> { - assert!(layers.len() <= u32::MAX as usize); + self.assert_layers_validity(layers); let info = sys::FrameEndInfo { ty: sys::FrameEndInfo::TYPE, next: ptr::null(), @@ -139,8 +139,8 @@ impl FrameStream { layers: &[&CompositionLayerBase<'_, G>], secondary_info: SecondaryEndInfo<'_, '_, '_, G>, ) -> Result<()> { - assert!(layers.len() <= u32::MAX as usize); - assert!(secondary_info.layers.len() <= u32::MAX as usize); + self.assert_layers_validity(layers); + self.assert_layers_validity(secondary_info.layers); let single_secondary_info = [sys::SecondaryViewConfigurationLayerInfoMSFT { ty: sys::SecondaryViewConfigurationLayerInfoMSFT::TYPE, next: ptr::null(), @@ -174,4 +174,97 @@ impl FrameStream { fn fp(&self) -> &raw::Instance { self.session.instance().fp() } + + /// Check the invariants of the passed `layers`. + /// The lifetimes guarantee the validity of non-null handles. + fn assert_layers_validity(&self, layers: &[&CompositionLayerBase<'_, G>]) { + // TODO `space` and `swapchain` must be from the same session (only in the spec for cube) + assert!(layers.len() <= u32::MAX as usize); + for &layer in layers { + match layer.as_raw().ty { + sys::CompositionLayerProjection::TYPE => { + let layer = unsafe { + std::mem::transmute::< + &CompositionLayerBase, + &CompositionLayerProjection, + >(layer) + } + .as_raw(); + assert_ne!(layer.space, sys::Space::NULL); + assert!(layer.view_count > 0); + let views = unsafe { + std::slice::from_raw_parts(layer.views, layer.view_count as usize) + }; + for view in views { + assert_ne!(view.sub_image.swapchain, sys::Swapchain::NULL); + } + } + sys::CompositionLayerQuad::TYPE => { + let layer = unsafe { + std::mem::transmute::<&CompositionLayerBase, &CompositionLayerQuad>( + layer, + ) + } + .as_raw(); + assert_ne!(layer.space, sys::Space::NULL); + assert_ne!(layer.sub_image.swapchain, sys::Swapchain::NULL); + } + sys::CompositionLayerCylinderKHR::TYPE => { + assert!(self + .session + .instance() + .exts() + .khr_composition_layer_cylinder + .is_some()); + let layer = unsafe { + std::mem::transmute::< + &CompositionLayerBase, + &CompositionLayerCylinderKHR, + >(layer) + } + .as_raw(); + assert_ne!(layer.space, sys::Space::NULL); + assert_ne!(layer.sub_image.swapchain, sys::Swapchain::NULL); + } + sys::CompositionLayerCubeKHR::TYPE => { + assert!(self + .session + .instance() + .exts() + .khr_composition_layer_cube + .is_some()); + let layer = + unsafe { + std::mem::transmute::< + &CompositionLayerBase, + &CompositionLayerCubeKHR, + >(layer) + } + .as_raw(); + assert_ne!(layer.space, sys::Space::NULL); + assert_ne!(layer.swapchain, sys::Swapchain::NULL); + } + sys::CompositionLayerEquirectKHR::TYPE => { + assert!(self + .session + .instance() + .exts() + .khr_composition_layer_equirect + .is_some()); + let layer = unsafe { + std::mem::transmute::< + &CompositionLayerBase, + &CompositionLayerEquirectKHR, + >(layer) + } + .as_raw(); + assert_ne!(layer.space, sys::Space::NULL); + assert_ne!(layer.sub_image.swapchain, sys::Swapchain::NULL); + } + ty => { + panic!("unsupported layer type: {:?}", ty) + } + } + } + } } diff --git a/openxr/src/generated.rs b/openxr/src/generated.rs index 921e93d1..62bf8a7f 100644 --- a/openxr/src/generated.rs +++ b/openxr/src/generated.rs @@ -7269,9 +7269,15 @@ pub(crate) mod builder { } #[repr(transparent)] pub struct CompositionLayerBase<'a, G: Graphics> { - _inner: sys::CompositionLayerBaseHeader, + inner: sys::CompositionLayerBaseHeader, _marker: PhantomData<&'a G>, } + impl<'a, G: Graphics> CompositionLayerBase<'a, G> { + #[inline] + pub(crate) fn as_raw(&self) -> &sys::CompositionLayerBaseHeader { + &self.inner + } + } #[derive(Copy, Clone)] #[repr(transparent)] pub struct CompositionLayerProjection<'a, G: Graphics> { @@ -7691,9 +7697,15 @@ pub(crate) mod builder { } #[repr(transparent)] pub struct HapticBase<'a> { - _inner: sys::HapticBaseHeader, + inner: sys::HapticBaseHeader, _marker: PhantomData<&'a ()>, } + impl<'a> HapticBase<'a> { + #[inline] + pub(crate) fn as_raw(&self) -> &sys::HapticBaseHeader { + &self.inner + } + } #[derive(Copy, Clone)] #[repr(transparent)] pub struct HapticVibration<'a> {