启用VK_KHR_SWAPCHAIN扩展后vkCreateInstance触发访问权限违规错误排查
野指针引发内存访问违规
你在paste_create_info函数中定义的device_extensions是局部vector,当函数执行完毕返回VkInstanceCreateInfo时,这个局部vector会被销毁,其内部占用的内存也会被释放。但你将create_info.ppEnabledExtensionNames赋值为device_extensions.data(),也就是指向这个局部vector的内存地址。等回到create_vulkan函数调用vkCreateInstance时,这个指针已经变成野指针,指向的内存已无效,此时访问就会触发权限违规错误。扩展类型误用
VK_KHR_SWAPCHAIN_EXTENSION_NAME是设备级扩展,只能在创建Vulkan逻辑设备时启用,不能在创建实例(vkCreateInstance)阶段添加到实例扩展列表中,这属于概念性错误。
步骤1:修正扩展类型错误
立即把VK_KHR_SWAPCHAIN_EXTENSION_NAME从实例扩展列表中移除,将其放到后续创建逻辑设备的扩展列表里。
步骤2:解决野指针问题
以下两种实现方式简单可靠:
方式一:将扩展容器提升为类成员变量
修改VulkanManager类,添加成员变量存储实例扩展:
class VulkanManager { private: std::vector<const char*> m_instance_extensions; // 其他成员变量... };
然后修改paste_create_info函数,使用成员变量存储扩展:
VkInstanceCreateInfo VulkanManager::paste_create_info(VkApplicationInfo* app_info) { VkInstanceCreateInfo create_info{}; m_instance_extensions.clear(); uint32_t glfw_extensions_count = 0; const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extensions_count); for (uint32_t i = 0; i < glfw_extensions_count; i++) m_instance_extensions.push_back(glfw_extensions[i]); create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.pApplicationInfo = app_info; create_info.enabledExtensionCount = static_cast<uint32_t>(m_instance_extensions.size()); create_info.ppEnabledExtensionNames = m_instance_extensions.data(); create_info.enabledLayerCount = 0; return create_info; }
这样m_instance_extensions的生命周期与VulkanManager实例一致,调用vkCreateInstance时内存仍处于有效状态。
方式二:在create_vulkan函数内管理扩展容器
调整代码结构,把扩展容器的创建放到create_vulkan函数中,再传递给构造VkInstanceCreateInfo的函数:
// 修改paste_create_info,接收外部扩展容器的引用 VkInstanceCreateInfo VulkanManager::paste_create_info(VkApplicationInfo* app_info, const std::vector<const char*>& instance_extensions) { VkInstanceCreateInfo create_info{}; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.pApplicationInfo = app_info; create_info.enabledExtensionCount = static_cast<uint32_t>(instance_extensions.size()); create_info.ppEnabledExtensionNames = instance_extensions.data(); create_info.enabledLayerCount = 0; return create_info; } // 修改create_vulkan函数 void VulkanManager::create_vulkan() { VkApplicationInfo app_info = VulkanManager::paste_app_info(); std::vector<const char*> instance_extensions; uint32_t glfw_extensions_count = 0; const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extensions_count); for (uint32_t i = 0; i < glfw_extensions_count; i++) instance_extensions.push_back(glfw_extensions[i]); VkInstanceCreateInfo create_info = VulkanManager::paste_create_info(&app_info, instance_extensions); // 此处调用vkCreateInstance VkInstance instance; VkResult result = vkCreateInstance(&create_info, nullptr, &instance); // 错误检查逻辑... }
这种方式下,instance_extensions的生命周期覆盖了vkCreateInstance的调用过程,指针不会失效。
补充:设备扩展的正确启用时机
当后续创建逻辑设备时,再添加VK_KHR_SWAPCHAIN_EXTENSION_NAME:
// 示例:创建逻辑设备时启用交换链扩展 std::vector<const char*> device_extensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; VkDeviceCreateInfo device_create_info{}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; // 其他参数设置... device_create_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size()); device_create_info.ppEnabledExtensionNames = device_extensions.data();
内容的提问来源于stack exchange,提问作者Mezim

