启用Address Sanitizer时Windows打开对话框永久无响应如何解决?
问题产生原因
这是Windows平台Address Sanitizer(ASAN)的已知兼容问题,触发根因如下:
- IFileOpenDialog的
Show方法运行时会加载大量系统Shell组件、第三方注册的Shell扩展程序,这些二进制文件默认没有经过ASAN插桩编译 - ASAN默认会全局Hook内存分配/释放、线程局部存储操作等系统API,对无插桩模块的内存操作进行检查时会出现未定义行为,部分场景下会触发死锁,导致对话框永久挂起
- 部分版本的ASAN默认启用的内存泄漏检测逻辑,会和模态文件对话框内部的STA线程消息循环、COM对象生命周期管理逻辑产生冲突,进一步提升挂起概率
可行解决方案
你可以根据实际场景选择以下任意一种方案解决:
- 方案1:调整ASAN运行时参数(最便捷)
在程序入口最开头添加代码,设置ASAN运行时配置,禁用冲突的检查项:
也可以在运行程序前手动设置系统环境变量// 放在wWinMain最开头,所有逻辑之前执行 _putenv_s("ASAN_OPTIONS", "detect_leaks=0 windows_hook_legacy_allocators=0 intercept_tls_get_addr=0");ASAN_OPTIONS为上述值,效果一致。 - 方案2:使用兼容的旧版文件对话框API
改用Win32传统的GetOpenFileNameAPI实现文件选择逻辑,该API触发ASAN冲突的概率远低于COM架构的IFileOpenDialog。 - 方案3:仅在非ASAN编译配置下使用IFileOpenDialog
用预处理宏包裹相关代码,调试阶段启用ASAN时走简化逻辑或者使用GetOpenFileName,Release发布时再用IFileOpenDialog:#ifdef __SANITIZE_ADDRESS__ // ASAN编译时走GetOpenFileName逻辑 #else // 正常编译时走原有IFileOpenDialog逻辑 #endif - 方案4:禁用ASAN对Shell模块的拦截(Visual Studio独有)
如果使用Visual Studio编译,可以在项目属性->C/C++->Address Sanitizer配置页,关闭「拦截系统分配器」「启用泄漏检测」两个选项,也可解决冲突。
内容的提问来源于stack exchange,提问作者mohammad-ghasemi-2549
相关产品推荐
相关产品推荐

