【问题标题】:How I'm supposed to use the sanitizer in clang?我应该如何在clang中使用消毒剂?
【发布时间】:2014-03-27 21:46:44
【问题描述】:

很抱歉,如果这是一个超级简单的概念,但我发现很难获得正确的心态才能正确使用clang 提供的消毒剂。

float foo(float f) { return (f / 0); }

我用这个小sn-p编译

clang++ -fsanitize=float-divide-by-zero -std=c++11 -stdlib=libc++ -c source.cpp -o osan

我还编译了我的对象的“正常”版本而不使用消毒剂

clang++ -std=c++11 -stdlib=libc++ -c source.cpp -o onorm

我期待一些详细的输出,或者来自控制台的一些错误,但是在使用 nm 检查文件时,我只发现了 1 个不同

nm o* --demangle

onorm:
0000000000000000 T foo(float)

osan:
                 U __ubsan_handle_divrem_overflow
0000000000000000 T foo(float)

所以在净化版本中有一个未定义的符号,其名称类似于我在编译时使用的净化器;但一切都是真正的“沉默”,clang前端根本没有输出。

我应该如何使用消毒剂以及正确的工作流程是什么?那个未定义的符号有什么意义?

【问题讨论】:

  • 您应该将您的程序链接到可执行文件并运行它。消毒剂是运行时工具。
  • @osgx 有趣的是,在文档中,我发现没有人编译和运行带有 main 函数的东西......所以我知道这是编译时间工具。
  • user2485710,哪些文档? Clang 的手册说 clang.llvm.org/docs/UsersManual.html “控制代码生成 ... -fsanitize=... 为各种形式的未定义或可疑行为打开 运行时检查 .... 如果检查失败,则会显示诊断消息在运行时产生解释问题。"
  • @osgx 来自 llvm 项目的文档,我没有它们的链接,可能它是与源代码本身一起分发的,但实际上它有点令人困惑,并让我想到了消毒剂 。在开始任何关于此的教程之前,应该更加强调“运行时”阶段。
  • @osgx 不,肯定不是那个页面。

标签: c++ clang llvm sanitizer


【解决方案1】:

未定义符号是一个实现消毒剂检查的函数。如果您查看生成的代码:

没有消毒剂:

_Z3foof:                                # @_Z3foof
    .cfi_startproc
# BB#0:
    xorps   %xmm1, %xmm1
    divss   %xmm1, %xmm0
    ret

使用消毒剂:

_Z3foof:                                # @_Z3foof
    .cfi_startproc
    .long   1413876459              # 0x54460aeb
    .quad   _ZTIFffE
# BB#0:
    pushq   %rax
.Ltmp1:
    .cfi_def_cfa_offset 16
    movss   %xmm0, 4(%rsp)          # 4-byte Spill
    movd    %xmm0, %esi
    movl    $__unnamed_1, %edi
    xorl    %edx, %edx
    callq   __ubsan_handle_divrem_overflow
    xorps   %xmm1, %xmm1
    movss   4(%rsp), %xmm0          # 4-byte Reload
    divss   %xmm1, %xmm0
    popq    %rax
    ret

您会看到它添加了使用该函数进行检查的代码。

编译器应该自动链接到适当的清理库,然后对我来说是下面的完整程序:

float foo(float f) { return (f / 0); }
int main() {
    foo(1.0f);
}

执行时产生以下输出:

main.cpp:1:32: runtime error: division by zero

我使用命令 clang++ -fsanitize=undefined main.cpp && ./a.out 构建和运行


如果您想要编译时检查,您想要启用更多编译器警告或静态分析器。但是,似乎没有针对浮点除零错误的任何警告或静态分析检查。

这是一个生成分析报告的程序:

#include <malloc.h>

int main() {
    int *i = (int*) malloc(sizeof(int));
}

使用clang++ -std=c++11 main.cpp 编译时不会产生任何诊断信息,但使用clang++ -std=c++11 --analyze main.cpp 编译时会报告以下内容:

main.cpp:4:10: warning: Value stored to 'i' during its initialization is never read
    int *i = (int*) malloc(sizeof(int));
         ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:1: warning: Potential leak of memory pointed to by 'i'
}
^

dead store 也可以用 -Weverything [-Wunused-value] 检测到,但泄漏只能由分析器检测到。

默认情况下,完整的分析结果会写入 plist 文件。您还可以使用以下命令运行分析器:

clang++ --analyze -Xanalyzer -analyzer-output=text main.cpp
clang++ --analyze -Xanalyzer -analyzer-output=html -o html-dir main.cpp

分别在标准输出或通过带注释源代码的 html 显示而不是在 plist 中获取检测到的问题的详细演练。

分析器检查列出here

请注意,为了达到最佳效果,分析器需要分析整个程序,这意味着它需要与构建系统相关联。通常的界面是通过 IDE (Xcode) 或带有 make 的 scan-build 工具。 CMake 具有一些 clang 功能,例如生成 clang JSON compilation database files,但我不确定 CMake 是否有任何内置支持 clang 分析器。

【讨论】:

  • 您使用了哪些编译器选项来编译它?
  • @user2485710 clang++ -fsanitize=undefined main.cpp &amp;&amp; ./a.out
  • 你没有动态链接库吗?这对我有用,但看起来涉及的 llvm 库是静态链接的。
  • @user2485710 是的,我认为它是静态链接的,尽管我知道 llvm 也为消毒剂构建动态库。您可以给 clang 提供-v 选项,以查看驱动程序在幕后使用来进行编译/链接的确切命令和参数。
  • 感谢您的精彩补充,静态分析也按预期工作。
【解决方案2】:

因此,如果我们查看 Controlling Code Generation 中的文档,它会说(强调我的):

为各种形式的未定义或可疑行为打开运行时检查

此选项控制 Clang 是否为各种形式的未定义或可疑行为添加运行时检查,默认情况下禁用。如果检查失败,会在运行时生成诊断消息,解释问题

所以这些是运行时检查而不是编译时检查。因此,如果您在代码中使用了foo,那么您将看到以下输出:

运行时错误:除以零

使用-fsanitize=undefined查看此示例live

float foo(float f) { return (f / 0); }

int main()
{
    int x = 1 << 100 ;
    foo( 2.0f ) ;
}

它会生成两条运行时消息:

main.cpp:6:19: 运行时错误:移位指数 100 对于 32 位类型“int”来说太大

main.cpp:2:36: 运行时错误:除以零

更新

关于静态检查器,在我对A C++ implementation that detects undefined behavior? 的回答中,我提到了几个工具:STACKkcc,当然还有Frama-C

显然clang 允许您使用--analyze to run it's static checker,但它似乎最终可能会被禁用,并且运行它的正确方法是通过scan-build

在我的自我回答问题Why do constant expressions have an exclusion for undefined behavior? 中,我展示了如何使用constexprs 在编译时捕获未定义的行为。

【讨论】:

  • 啊,是的。如果他期望编译时检查消毒剂是错误的工具。静态分析器会进行更多的编译时检查。
  • 现在我明白了这一点,但我仍然认为它可能对更详细的输出更有用。 llvm/clang 的静态参考分析器是什么?
  • @user2485710 我对A C++ implementation that detects undefined behavior? 的回答对静态检查器有一些很好的参考。
  • 所以 clang 项目提供了消毒剂但不提供静态分析器?我必须为此参考其他项目?
  • 我会回答我自己的问题:显然 clang-analyzer.llvm.org/scan-build.html 页面并没有提到该工具已经与 clang 源一起分发的事实......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-24
  • 2016-08-26
  • 1970-01-01
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-03-10
相关资源
最近更新 更多