如何使AddressSanitizer在出现错误后不停止(以及其他问题)

32

我正在使用OS X 10.8.5操作系统,通过Homebrew安装了llvm 3.4(clang版本为3.4(tags / RELEASE_34 / final)),并使用-fsanitize = address进行构建。我可以在简单的演示程序中使用asan,但是在针对我们的代码库进行构建时,我遇到了一些问题(尽管我只想得到#1的答案):

  1. 第三方库正在生成asan错误,并且asan在第一次发生错误时终止了我的应用程序。我认为会有某种(运行时/编译时)选项告诉asan在找到错误后继续执行。具体来说,我看到了这个:

bash-3.2$ ASAN_SYMBOLIZER_PATH=/usr/local/Cellar/llvm34/3.4/lib/llvm-3.4/bin/llvm-symbolizer ./unit_test
Start testing of PathTrieTest
Config: Using QTest library 4.8.2, Qt 4.8.2
PASS   : PathTrieTest::initTestCase()
PASS   : PathTrieTest::pathTrieNodeTest()
=================================================================
==76647==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61600019e588 at pc 0x10891ddd3 bp 0x11312ba90 sp 0x11312ba58
WRITE of size 48830 at 0x61600019e588 thread T3
    #0 0x10891ddd2 in wrap_readdir_r (/usr/local/lib/llvm-3.4/lib/clang/3.4/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x11dd2)
    #1 0x10ac23571 in QFileSystemIterator::advance(QFileSystemEntry&, QFileSystemMetaData&) (/Volumes/ToolChain/qt-4.8/lib/QtCore.framework/Versions/4/QtCore+0xef571)
    #2 0x10abd86d3 in QDirIteratorPrivate::advance() (/Volumes/ToolChain/qt-4.8/lib/QtCore.framework/Versions/4/QtCore+0xa46d3)
    #3 0x10abd7a7f in QDirIteratorPrivate::QDirIteratorPrivate(QFileSystemEntry const&, QStringList const&, QFlags<QDir::Filter>, QFlags<QDirIterator::IteratorFlag>, bool) (/Volumes/ToolChain/qt-4.8/lib/QtCore.framework/Versions/4/QtCore+0xa3a7f)
    #4 0x10abd8b68 in QDirIterator::QDirIterator(QDir const&, QFlags<QDirIterator::IteratorFlag>) (/Volumes/ToolChain/qt-4.8/lib/QtCore.framework/Versions/4/QtCore+0xa4b68)
    #5 0x10abd7609 in QDirPrivate::initFileLists(QDir const&) const (/Volumes/ToolChain/qt-4.8/lib/QtCore.framework/Versions/4/QtCore+0xa3609)
    #6 0x10abd5394 in QDir::count() const (/Volumes/ToolChain/qt-4.8/lib/QtCore.framework/Versions/4/QtCore+0xa1394)
    #7 0x1084c205d in get_count(QFileInfo&) /Users/stebro/dev_vm/ui/ui/fsinfoprovider.cpp:36
...

当程序在未经过净化的情况下运行时,此错误不会导致应用程序终止。

  • 当我使用-fsanitize=undefined(或-fsanitize=address,undefined)选项时,我无法使代码链接起来。 我在编译和链接命令中都包含了-fsanitize=undefined行,但我会收到链接错误,例如:

        Undefined symbols for architecture x86_64:
          "typeinfo for __cxxabiv1::__class_type_info", referenced from:
              __ubsan::checkDynamicType(void*, void*, unsigned long) in libclang_rt.ubsan_osx.a(ubsan_type_hash.o)
              isDerivedFromAtOffset(__cxxabiv1::__class_type_info const*, __cxxabiv1::__class_type_info const*, long) in libclang_rt.ubsan_osx.a(ubsan_type_hash.o)
              findBaseAtOffset(__cxxabiv1::__class_type_info const*, long) in libclang_rt.ubsan_osx.a(ubsan_type_hash.o)
        "typeinfo for __cxxabiv1::__si_class_type_info", referenced from:
              isDerivedFromAtOffset(__cxxabiv1::__class_type_info const*, __cxxabiv1::__class_type_info const*, long) in libclang_rt.ubsan_osx.a(ubsan_type_hash.o)
              findBaseAtOffset(__cxxabiv1::__class_type_info const*, long) in libclang_rt.ubsan_osx.a(ubsan_type_hash.o)
        "typeinfo for __cxxabiv1::__vmi_class_type_info", referenced from:
              isDerivedFromAtOffset(__cxxabiv1::__class_type_info const*, __cxxabiv1::__class_type_info const*, long) in libclang_rt.ubsan_osx.a(ubsan_type_hash.o)
              findBaseAtOffset(__cxxabiv1::__class_type_info const*, long) in libclang_rt.ubsan_osx.a(ubsan_type_hash.o)
    
    我无法让黑名单起作用,而-mllvm -asan-globals=0或-mllvm -asan-stack=0似乎不像我预期的那样工作。例如,后者不能禁止生成上述#1中列出的错误,并创建类似下面的黑名单也无法抑制错误:

  • fun:QDirPrivate::initFileLists
    fun:get_count
    fun:*opendir2*
    
  • 最后,使用这些asan选项生成的可执行文件会导致lldb崩溃。我正在使用XCode 5工具附带的lldb;homebew llvm软件包中没有部署lldb,并且我无法弄清楚如何构建它。构建说明enter link description here有一个指向你应该使用的源代码的失效链接;直接从svn存储库中拉取源代码,使用:

    svn co http://llvm.org/svn/llvm-project/lldb/tags/RELEASE_34/final lldb
    

    结果会产生无法编译的代码(可根据请求提供错误信息)。


  • 我找到了一个解决Qt堆溢出问题的方法。我在下面发布了答案。 - rryan
    3个回答

    38

    1
    这似乎是自我提问以来新增的新功能。感谢更新。 - Steve Broberg
    ASAN_OPTIONS在Windows上无法工作,我尝试了以上示例,当我输入ASAN_OPTIONS时,它会给出未识别选项的提示。在Ubuntu上可以正常工作。 - Jon marsh
    1
    如何在 MAC 上使用环境变量 ASAN_OPTIONS=halt_on_error=0 运行? - YuFeng Shen
    在macOS上似乎被忽略了。无论是禁用特定类型的错误还是使用抑制文件,都似乎没有得到尊重。有人知道如何在没有Xcode的情况下在macOS上使用ASAN吗? - oarfish
    这似乎只打印第一个错误。有什么办法可以打印多个ASAN错误吗? - Ilia Sidorenko

    5
    1. 可寻址性错误(特别是像您提到的OOB写入这样的内存损坏)通常足够严重,需要引起关注。忽略它们不能撤消它们的影响,并且在跳过堆损坏后,程序很可能会在完全不相关的地方崩溃。 您可以尝试使用禁用readdir_r检查的自己构建的Clang,但我建议首先尝试修复错误。
    2. 请在http://code.google.com/p/address-sanitizer上提交带有重现步骤的错误报告。
    3. 黑名单仅通过不对其进行检测来禁用黑名单函数中的可寻址性检查,它们不会检查某些帧的堆栈。您的特定检查发生在编译到运行时库中的函数拦截器中,因此您甚至无法将其列入黑名单。如果#1中的错误出现在某个系统库中并且无法轻松解决,我们可以考虑添加运行时选项以禁用readdir_r检查。
    4. 再次感谢您提交错误报告。

    1
    禁用AddressSanitizer错误的合法用例是:我想要查看整个程序生成了多少AddressSanitizer,而不仅仅是它是否存在0或> = 1个错误。 - Ilia Sidorenko

    1

    顺便说一下 - 如果你正在从源代码构建Qt,则我找到了一个解决堆溢出问题的方法。 我认为问题与32位/64位inode有关(由于某种原因,在我构建Qt时未定义_DARWIN_FEATURE_64_BIT_INODE)。

    diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp
    index 029b989..76b176f 100644
    --- a/src/corelib/io/qfilesystemiterator_unix.cpp
    +++ b/src/corelib/io/qfilesystemiterator_unix.cpp
    @@ -75,6 +75,7 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi
             size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX);
             if (maxPathName == size_t(-1))
                 maxPathName = FILENAME_MAX;
    +        maxPathName = 99999;
             maxPathName += sizeof(QT_DIRENT) + 1;
    QT_DIRENT *p = reinterpret_cast(::malloc(maxPathName));

    谢谢。我们已经转移到Qt5,问题似乎已经消失了。 - Steve Broberg

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接