工厂方法创建的PipelineViewportStateCreateInfo结构体成员丢失值
问题根源:悬垂指针引发的未定义行为
你遇到的核心问题是工厂函数返回的PipelineViewportStateCreateInfo引用了函数内部栈上的临时变量。当工厂函数执行完毕,栈上的视口数据(比如Viewport数组)会被销毁,此时PipelineViewportStateCreateInfo中的pViewports指针就变成了悬垂指针。后续调用GraphicsPipelineCreateInfoBuilder::build时,访问这个指针指向的内存会触发未定义行为,原本正确的宽高值就变成了0(或其他垃圾值)。
为什么编译器没有提示?
Rust的安全检查仅针对安全指针(&/&mut),而Vulkan的C风格结构体使用的是裸指针(*const/*mut),属于unsafe范畴。编译器无法跟踪裸指针的生命周期,也不会强制检查其指向的内存是否有效。这种内存安全问题需要开发者手动管理,编译器不会主动进行防护。
解决方案
1. 绑定视口数据与创建信息的生命周期
将视口数据和对应的创建信息打包在同一个结构体中,确保数据的所有权和生命周期与创建信息绑定,避免悬垂指针:
use ash::vk; struct ViewportState { viewports: Vec<vk::Viewport>, create_info: vk::PipelineViewportStateCreateInfo, } fn create_viewport_state(extent: &vk::SwapchainExtent2D) -> ViewportState { let viewport = vk::Viewport { width: extent.width as f32, height: extent.height as f32, min_depth: 0.0, max_depth: 1.0, x: 0.0, y: 0.0, }; let mut viewports = Vec::new(); viewports.push(viewport); let create_info = vk::PipelineViewportStateCreateInfo { s_type: vk::StructureType::PIPELINE_VIEWPORT_STATE_CREATE_INFO, p_next: std::ptr::null(), flags: vk::PipelineViewportStateCreateFlags::empty(), viewport_count: 1, p_viewports: viewports.as_ptr(), scissor_count: 1, p_scissors: &[vk::Rect2D { offset: vk::Offset2D { x: 0, y: 0 }, extent: *extent, }].as_ptr(), }; ViewportState { viewports, create_info } }
使用时,只要ViewportState实例未被销毁,create_info中的指针就始终有效。
2. 避免在工厂函数内创建临时栈数据
不要在工厂函数中创建栈上的视口数组,而是让调用方提供具有足够生命周期的视口数据,或者在工厂函数中使用堆分配的数据(比如Vec)来存储视口,确保数据在创建管线的过程中不会被释放。
3. 检查Vulkan绑定库的builder行为
部分Vulkan Rust绑定库(如ash)的builder可能不会自动复制指针指向的数据,仅保存指针本身。务必确认builder的文档,确保指针指向的数据在build调用时仍然有效。
内容的提问来源于stack exchange,提问作者Rens Verhage

