MSVC 中的地址消毒器:为啥它在启动时报告错误?

Posted

技术标签:

【中文标题】MSVC 中的地址消毒器:为啥它在启动时报告错误?【英文标题】:Address Sanitizer in MSVC: why does it report an error on startup?MSVC 中的地址消毒器:为什么它在启动时报告错误? 【发布时间】:2021-12-09 04:55:22 【问题描述】:

我正在尝试将 Qt 与 MSVC 2019 与 Address Sanitizer 结合使用的项目。我使用 Address Sanitizer 构建了项目,但没有重建所有库,包括 Qt。

它在资源初始化时在 Qt 内部崩溃(在调用堆栈中使用 qRegisterResourceData)。

这是:

滥用地址清理程序,比如,我也应该用它重建 Qt DLL? 我应该深入研究 Qt 中的问题? 已知的 Qt 问题?

我已经在向导默认创建的小部件应用程序中重新创建了问题。调用栈如下:

>   KernelBase.dll!RaiseException() Unknown
    QtWidgetsApplication1.exe!__vcasan::OnAsanReport(const char * description, const char * report, bool __throw) Line 602  C++
    QtWidgetsApplication1.exe!__vcasan::ReportCallback(const char * szReport) Line 325  C++
    clang_rt.asan_dbg_dynamic-x86_64.dll!__asan::ScopedInErrorReport::~ScopedInErrorReport(void)    Unknown
    clang_rt.asan_dbg_dynamic-x86_64.dll!__asan::ReportMallocUsableSizeNotOwned(unsigned __int64,struct __sanitizer::BufferedStackTrace *)  Unknown
    clang_rt.asan_dbg_dynamic-x86_64.dll!__asan::asan_malloc_usable_size(void const *,unsigned __int64,unsigned __int64)    Unknown
    clang_rt.asan_dbg_dynamic-x86_64.dll!_recalloc()    Unknown
    ucrtbased.dll!_register_onexit_function::__l2::<lambda>() Line 112  C++
    ucrtbased.dll!__crt_seh_guarded_call<int>::operator()<void <lambda>(void),int <lambda>(void) &,void <lambda>(void)>(__acrt_lock_and_call::__l2::void <lambda>(void) && setup, _register_onexit_function::__l2::int <lambda>(void) & action, __acrt_lock_and_call::__l2::void <lambda>(void) && cleanup) Line 204    C++
    ucrtbased.dll!__acrt_lock_and_call<int <lambda>(void)>(const __acrt_lock_id lock_id, _register_onexit_function::__l2::int <lambda>(void) && action) Line 980    C++
    ucrtbased.dll!_register_onexit_function(_onexit_table_t * table, int(*)() function) Line 149    C++
    Qt5Cored.dll!_onexit(int(*)() function) Line 267    C++
    Qt5Cored.dll!atexit(void(*)() function) Line 275    C++
    Qt5Cored.dll!QPropertyAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) Line 268   C++
    Qt5Cored.dll!QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) Line 991   C++
    Qt5Cored.dll!QAbstractAnimation::start(QAbstractAnimation::DeletionPolicy policy) Line 1362 C++
    Qt5Widgetsd.dll!QWidgetAnimator::animate(QWidget * widget, const QRect & _final_geometry, bool animate) Line 114    C++
    Qt5Widgetsd.dll!QToolBarAreaLayout::apply(bool animate) Line 936    C++
    Qt5Widgetsd.dll!QMainWindowLayoutState::apply(bool animated) Line 687   C++
    Qt5Widgetsd.dll!QMainWindowLayout::applyState(QMainWindowLayoutState & newState, bool animate) Line 2759    C++
    Qt5Widgetsd.dll!QMainWindowLayout::setGeometry(const QRect & _r) Line 1979  C++
    Qt5Widgetsd.dll!QLayoutPrivate::doResize() Line 596 C++
    Qt5Widgetsd.dll!QLayout::activate() Line 1119   C++
    Qt5Widgetsd.dll!QWidgetPrivate::setVisible(bool visible) Line 8083  C++
    Qt5Widgetsd.dll!QWidget::setVisible(bool visible) Line 8044 C++
    Qt5Widgetsd.dll!QWidget::show() Line 7670   C++
    QtWidgetsApplication1.exe!main(int argc, char * * argv) Line 9  C++
    QtWidgetsApplication1.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) Line 97    C++
    QtWidgetsApplication1.exe!invoke_main() Line 107    C++
    QtWidgetsApplication1.exe!__scrt_common_main_seh() Line 288 C++
    QtWidgetsApplication1.exe!__scrt_common_main() Line 331 C++
    QtWidgetsApplication1.exe!WinMainCRTStartup(void * __formal) Line 17    C++
    kernel32.dll!BaseThreadInitThunk()  Unknown
    ntdll.dll!RtlUserThreadStart()  Unknown

输出:

Address 0x01c416f8eda0 is a wild pointer.
SUMMARY: AddressSanitizer: bad-malloc_usable_size (C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\bin\HostX86\x64\clang_rt.asan_dbg_dynamic-x86_64.dll+0x18004e63a) in _asan_wrap_GlobalSize+0x4b948
Address Sanitizer Error: bad-malloc_usable_size

【问题讨论】:

请提供崩溃报告(至少崩溃的线程调用堆栈)。 我在这个话题上可能已经过时了,但不久前(CppCon 20)避免重新编译所有库的唯一选择是将“父”可执行文件静态链接到 asan 库 - devblogs.microsoft.com/cppblog/… 报告给开发者社区developercommunity.visualstudio.com/t/… 【参考方案1】:

问题是加载顺序

Qt 恰好在 ASan 之前加载,并且在加载 ASan DLL 之前加载 C/C++ 运行时。 Qt 执行一些初始化。所以内存是 malloced 没有 ASan 知识,后来 ASan 看到 realloc 而没有之前的 malloc,它会报告。

使用 ASan 构建 Qt 应该可以解决问题,我没有尝试过,因为我找到了不涉及 Qt 重建的解决方法。

解决方法:只需让 Qt DLL 导入 ASan DLL。对我来说是通过以下命令:

setdll /d:clang_rt.asan_dbg_dynamic-x86_64.dll <path_to_deployed_debug_app>\Qt5Cored.dll

setdll /d:clang_rt.asan_dynamic-x86_64.dll <path_to_deployed_release_app>\Qt5Core.dll

setdll 是 Detours 库中的一个工具,可以从 https://github.com/microsoft/Detours 获得,然后使用 nmake 构建。

clang_rt.asan_dynamic-x86_64.dllclang_rt.asan_dbg_dynamic-x86_64.dll 应该可以直接使用,或者在执行此操作时从%path% 获得,最方便的方法是从 VS Tools 命令提示符执行命令。

【讨论】:

感谢您的回复,我设法开始了工作,但似乎 VS2019 sanitizer 版本不跟踪泄漏。在 clang/gcc linux 版本中,不需要为此功能指定任何内容。 @Ghita,MSVC 中的地址清理程序目前是有限的,但我相信 VS2022 更新会添加更多功能。不过不确定是否有泄漏。 @Ghita,如果你的代码准备好用 clang-cl 工具集编译,你可以从那里尝试 ASan 是的。由于成熟,我最初尝试过。似乎我也需要用 clang-cl 重建 QT 并且没有找到如何去做。如果 QT 不是用它构建的,似乎存在某种二进制不兼容(链接时间):-) clang-cl 目标是二进制兼容,并且能够使用 MSVC STL 和 SDK 标头。因此,如果它无法链接 Qt 二进制文件,则可能值得调查并向bugs.llvm.org报告repro

以上是关于MSVC 中的地址消毒器:为啥它在启动时报告错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Cobertura 在通过 Eclipse 插件运行时报告 0% 覆盖率?

SVN中与资源库同步时报告了错误。1 中的 0 个资源已经同步

使用延迟作业发送电子邮件时报告错误

如何修复使用optimize.minimize()时报告的值错误但引用的函数没有错误?

Tensorflow 在训练 yolo 时报告了 CUDA_ERROR_ILLEGAL_ADDRESS 错误

为啥注入的任何 DLL 都会使主机进程崩溃?