g_array_append_vals断言失败及g_ptr_array_extend_and_steal崩溃问题排查
Vulkan扩展检查CMake项目崩溃问题解决
问题背景
开发Vulkan扩展检查的CMake项目时,程序运行后瞬间退出,终端输出断言失败错误。先后尝试GArray和GPtrArray两种容器,均遇到问题:
初始GArray实现的问题
使用GArray编写的函数触发g_array_append_vals的'array'断言失败,核心原因是未初始化requiredExtensions数组,指针类型转换尝试无效。
初始代码:
GArray* glfwExtensions, *requiredExtensions; uint_fast32_t glfwExtensionCount; bool enableValidationLayers = true; int __fastcall getRequiredExtensions() { glfwExtensions = g_array_new_take((char**)glfwGetRequiredInstanceExtensions(&glfwExtensionCount), glfwExtensionCount, false, __SIZEOF_POINTER__); g_array_append_vals(requiredExtensions, (const char**)(glfwExtensions->data), glfwExtensionCount); g_array_append_vals(requiredExtensions, (const char*[]){VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME}, 1); if (enableValidationLayers) g_array_append_vals(requiredExtensions, (const char*[]){VK_EXT_DEBUG_UTILS_EXTENSION_NAME}, 1); return EXIT_SUCCESS; }
终端错误输出:
(proces:8144): GLib-CRITICAL **: 16:31:15.244: g_array_append_vals: assertion 'array' failed (proces:8144): GLib-CRITICAL **: 16:31:15.260: g_array_append_vals: assertion 'array' failed (proces:8144): GLib-CRITICAL **: 16:31:15.261: g_array_append_vals: assertion 'array' failed
改用GPtrArray后的问题
切换到GPtrArray后,调用g_ptr_array_extend_and_steal时程序崩溃,但单独用g_ptr_array_add添加元素可以正常运行,导致无法批量启用验证层和其他扩展。
修改后代码:
GPtrArray *glfwExtensions, *requiredExtensions; uint_fast32_t glfwExtensionCount; bool enableValidationLayers = true; int __fastcall getRequiredExtensions() { { const char** glfwExtTemp = (const char**)glfwGetRequiredInstanceExtensions(&glfwExtensionCount); glfwExtensions = g_ptr_array_new_take((gpointer*)glfwExtTemp, glfwExtensionCount, NULL); requiredExtensions = g_ptr_array_copy(glfwExtensions, NULL, NULL); } // g_ptr_array_add(requiredExtensions, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); <-- 此代码正常运行,原因何在? g_ptr_array_extend_and_steal(requiredExtensions, g_ptr_array_new_take((gpointer*)(char*[]){ VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, }, 1, NULL)); if (enableValidationLayers) g_ptr_array_extend_and_steal(requiredExtensions, g_ptr_array_new_take((gpointer*)(char*[]){ VK_EXT_DEBUG_UTILS_EXTENSION_NAME, }, 1, NULL)); return EXIT_SUCCESS; }
问题原因分析
g_ptr_array_extend_and_steal崩溃的核心原因是临时栈数组的生命周期问题:
- 代码中
(char*[]){VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME}是栈上的临时数组,语句执行结束后会被销毁。 g_ptr_array_new_take会接管传入的指针数组所有权,但临时数组销毁后,GPtrArray内部持有了野指针。- 调用
g_ptr_array_extend_and_steal时访问这些野指针,触发程序崩溃。 - 而
g_ptr_array_add只是添加字符串字面量的指针,字符串字面量存储在程序全局只读数据区,生命周期贯穿整个程序,因此不会出现野指针问题。
解决方案
方案1:逐个调用g_ptr_array_add添加扩展
直接逐个添加扩展名称,避免临时数组的生命周期问题:
int __fastcall getRequiredExtensions() { const char** glfwExtTemp = (const char**)glfwGetRequiredInstanceExtensions(&glfwExtensionCount); glfwExtensions = g_ptr_array_new_take((gpointer*)glfwExtTemp, glfwExtensionCount, NULL); requiredExtensions = g_ptr_array_copy(glfwExtensions, NULL, NULL); // 逐个添加扩展 g_ptr_array_add(requiredExtensions, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); if (enableValidationLayers) { g_ptr_array_add(requiredExtensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } return EXIT_SUCCESS; }
方案2:动态分配数组后使用g_ptr_array_new_take
若需批量添加,可动态分配数组存储扩展名称,确保生命周期足够:
int __fastcall getRequiredExtensions() { const char** glfwExtTemp = (const char**)glfwGetRequiredInstanceExtensions(&glfwExtensionCount); glfwExtensions = g_ptr_array_new_take((gpointer*)glfwExtTemp, glfwExtensionCount, NULL); requiredExtensions = g_ptr_array_copy(glfwExtensions, NULL, NULL); // 动态分配数组存储扩展 gpointer* portabilityExt = g_new(gpointer, 1); portabilityExt[0] = (gpointer)VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; g_ptr_array_extend_and_steal(requiredExtensions, g_ptr_array_new_take(portabilityExt, 1, NULL)); if (enableValidationLayers) { gpointer* debugExt = g_new(gpointer, 1); debugExt[0] = (gpointer)VK_EXT_DEBUG_UTILS_EXTENSION_NAME; g_ptr_array_extend_and_steal(requiredExtensions, g_ptr_array_new_take(debugExt, 1, NULL)); } return EXIT_SUCCESS; }
方案3:使用g_ptr_array_addv批量添加
GLib提供g_ptr_array_addv函数,可直接批量添加指针数组,无需创建临时GPtrArray:
int __fastcall getRequiredExtensions() { const char** glfwExtTemp = (const char**)glfwGetRequiredInstanceExtensions(&glfwExtensionCount); glfwExtensions = g_ptr_array_new_take((gpointer*)glfwExtTemp, glfwExtensionCount, NULL); requiredExtensions = g_ptr_array_copy(glfwExtensions, NULL, NULL); // 批量添加扩展数组(末尾需以NULL结尾) const gpointer portabilityExts[] = { (gpointer)VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, NULL }; g_ptr_array_addv(requiredExtensions, portabilityExts); if (enableValidationLayers) { const gpointer debugExts[] = { (gpointer)VK_EXT_DEBUG_UTILS_EXTENSION_NAME, NULL }; g_ptr_array_addv(requiredExtensions, debugExts); } return EXIT_SUCCESS; }
内容的提问来源于stack exchange,提问作者Brain_driver_not_found
相关产品推荐
相关产品推荐

