From f78177793161e242c79650060cb35b0a210bda2e Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sun, 19 Dec 2021 12:33:39 +0100 Subject: [PATCH] examples: Use `slice::from_ref` to not loose lifetime on nested slices As per the readme `.build()` should only be called as late as possible, and only if absolutely necessary; such cases include slices that are passed directly to functions. More precisely, such build calls and the creation of temporary slices should happen inside the same expression as the function call to be sound and completely lifetime-checked. This pattern of `&[my_builder.build()]` is however not possible when constructing intermediary Vulkan objects that reference the slice. In the first place this slice goes out of scope after the expression that creates the Vulkan object, which is caught and disallowed by rustc (unless this expression itself ends in `.build()`, which is completely unsound as it makes rustc unable to validate this lifetime dependency). In the second place - and as is most relevant for this patch that removes `.build()` calls that were not surrounded by temporary slice constructors - said expression drops the lifetime checks on anything held by `my_builder` which _could_ go out of scope before the newly constructed Vulkan object is used, resulting yet again in Undefined Behaviour. Fortunately, for slices of size 1 which are typical in Vulkan, `std::slice::as_ref` exists which is analogous to taking a pointer to an object and considering it an array of length 1 in C(++). This maintains the lifetime through `Deref` and makes rustc able to fully check all lifetimes and prevent unsound code. Albeit improving overall consistency, the `&[my_builder.build()]` pattern is not substituted in aforementioned Vulkan function-call expressions as that is considered "extraneous" [1] and demonstrates the various ways to safely construct Vulkan objects for the observant reader. [1]: https://github.com/MaikKlein/ash/pull/506#discussion_r762630648 --- examples/src/bin/texture.rs | 7 +++---- examples/src/bin/triangle.rs | 7 +++---- examples/src/lib.rs | 7 +++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/examples/src/bin/texture.rs b/examples/src/bin/texture.rs index 902be28..e4ab27e 100644 --- a/examples/src/bin/texture.rs +++ b/examples/src/bin/texture.rs @@ -62,15 +62,14 @@ fn main() { ..Default::default() }]; - let subpasses = [vk::SubpassDescription::builder() + let subpass = vk::SubpassDescription::builder() .color_attachments(&color_attachment_refs) .depth_stencil_attachment(&depth_attachment_ref) - .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .build()]; + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS); let renderpass_create_info = vk::RenderPassCreateInfo::builder() .attachments(&renderpass_attachments) - .subpasses(&subpasses) + .subpasses(std::slice::from_ref(&subpass)) .dependencies(&dependencies); let renderpass = base diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 5c5f69b..cc322fc 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -51,15 +51,14 @@ fn main() { ..Default::default() }]; - let subpasses = [vk::SubpassDescription::builder() + let subpass = vk::SubpassDescription::builder() .color_attachments(&color_attachment_refs) .depth_stencil_attachment(&depth_attachment_ref) - .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .build()]; + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS); let renderpass_create_info = vk::RenderPassCreateInfo::builder() .attachments(&renderpass_attachments) - .subpasses(&subpasses) + .subpasses(std::slice::from_ref(&subpass)) .dependencies(&dependencies); let renderpass = base diff --git a/examples/src/lib.rs b/examples/src/lib.rs index f93e797..9d5513b 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -294,13 +294,12 @@ impl ExampleBase { }; let priorities = [1.0]; - let queue_info = [vk::DeviceQueueCreateInfo::builder() + let queue_info = vk::DeviceQueueCreateInfo::builder() .queue_family_index(queue_family_index) - .queue_priorities(&priorities) - .build()]; + .queue_priorities(&priorities); let device_create_info = vk::DeviceCreateInfo::builder() - .queue_create_infos(&queue_info) + .queue_create_infos(std::slice::from_ref(&queue_info)) .enabled_extension_names(&device_extension_names_raw) .enabled_features(&features);