使用Ash映射vkDeviceMemory时触发STATUS_ACCESS_VIOLATION错误
问题描述
使用Rust的Vulkan绑定库Ash开发时,将自定义模型加载器输出的索引缓冲区数据写入vkDeviceMemory时,调用index_slice.copy_from_slice(&index_buffer_data)触发STATUS_ACCESS_VIOLATION(退出码0xc0000005)崩溃。硬编码顶点和索引数据时程序正常运行,仅加载模型数据时出现问题。
问题原因分析
- 缓冲区大小计算错误:
代码中用std::mem::size_of_val(&index_buffer_data)计算缓冲区大小,但index_buffer_data是Vec<u32>类型,size_of_val返回的是Vec结构体自身的内存占用(通常为24字节),而非内部存储的所有u32元素的总字节数。硬编码数组时size_of_val能正确返回数组总字节数,因此无问题;但加载模型得到的Vec会导致缓冲区和分配的内存远小于实际需要的大小,复制数据时越界访问内存,触发崩溃。 - OBJ面数据解析逻辑存在缺陷:
自定义模型加载器解析OBJ的f行时,直接将分割后的字符串整体解析为u32,但OBJ标准面格式通常是顶点索引/纹理坐标索引/法线索引(如1/2/3),这种情况下str.parse::<u32>()会解析失败,虽代码用unwrap()忽略错误,但会导致索引数据异常,是潜在的崩溃诱因。 - Align结构体元素大小可能未正确初始化:
copy_from_slice方法依赖self.elem_size == size_of::<T>() as u64判断是否启用批量复制,若Align::new时未将elem_size设置为size_of::<u32>() as u64,会退化为循环复制逻辑,结合内存大小计算错误,同样会引发越界访问。
解决办法
- 修正缓冲区大小计算逻辑:
将缓冲区创建和内存分配的大小改为基于Vec元素数量和单个元素大小的计算,替换原有的size_of_val调用:
同步修改断言部分:let index_buffer_create_info = vk::BufferCreateInfo { size: (index_buffer_data.len() * std::mem::size_of::<u32>()) as u64, usage: vk::BufferUsageFlags::INDEX_BUFFER, sharing_mode: vk::SharingMode::EXCLUSIVE, ..Default::default() };assert_eq!( index_buffer_memory_req.size, (index_buffer_data.len() * std::mem::size_of::<u32>()) as u64 ); - 修复OBJ面数据解析逻辑:
针对OBJ标准面格式,分割每个顶点的索引部分,提取顶点索引(第一个数值):"f" => { for face_part in line_split[1..] { let parts: Vec<&str> = face_part.split('/').collect(); if let Some(vertex_idx_str) = parts.first() { let vertex_idx = vertex_idx_str.parse::<u32>().unwrap() - 1; index_buffer.push(vertex_idx); } } }, - 确保Align结构体初始化正确:
初始化Align时,将elem_size参数设置为std::mem::size_of::<u32>() as u64,保证批量复制的条件成立:
(注:需根据let mut index_slice = Align::new( index_ptr, std::mem::align_of::<u32>() as u64, std::mem::size_of::<u32>() as u64, index_buffer_memory_req.size );Align结构体的实际定义调整参数顺序,确保elem_size被正确赋值)
内容的提问来源于stack exchange,提问作者mahjong master
相关产品推荐
相关产品推荐

