简体   繁体   English

我怎么应该在铿锵声中使用消毒杀菌剂?

[英]How I'm supposed to use the sanitizer in clang?

I'm sorry if this is a uber-easy concept, but I find hard to acquire the right mindset in order to correctly use the sanitizer provided by clang . 我很抱歉,如果这是一个超级简单的概念,但我发现很难获得正确的心态,以便正确使用clang提供的消毒剂。

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

I compile this small snippet with 我编译这个小片段

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

and I also compile a "normal" version of my object without using the sanitizer 而且我还在不使用消毒剂的情况下编译了我的对象的“正常”版本

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

I was expecting some verbose output, or some error from the console, but when inspecting the file with nm I only found 1 difference 我期待一些冗长的输出,或者来自控制台的一些错误,但是当用nm检查文件时,我发现只有1个区别

nm o* --demangle

onorm:
0000000000000000 T foo(float)

osan:
                 U __ubsan_handle_divrem_overflow
0000000000000000 T foo(float)

So in the sanitized version there is an undefined symbol with a name that resembles the sanitizer that I was using when compiling this; 所以在清理版本中有一个未定义的符号,其名称类似于我在编译时使用的清洁剂; but everything is really "silent" with no output at all from the clang frontend . 但是一切都是“沉默的”,而且从铿锵的前端根本没有输出。

How I'm supposed to use the sanitizer and what is the right workflow ? 我应该如何使用消毒剂以及什么是正确的工作流程? What's the point of that undefined symbol ? 那个未定义的符号有什么意义?

The undefined symbol is a function that implements the sanitizer's check. 未定义的符号是实现清洁剂检查的功能。 If you look at generated code: 如果你看一下生成的代码:

No sanitizer: 没有消毒剂:

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

With sanitizer: 使用消毒剂:

_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

You see it's added the code to do the check using that function. 您看到它添加了使用该功能进行检查的代码。

The compiler should automatically link in the appropriate sanitizer library and then for me the following complete program: 编译器应自动链接到相应的清理程序库中,然后为我完成以下完整程序:

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

Produces the following output when executed: 执行时生成以下输出:

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

I built and ran using the command clang++ -fsanitize=undefined main.cpp && ./a.out 我使用命令clang++ -fsanitize=undefined main.cpp && ./a.out构建并运行


If you want compile-time checks you want to either enable more compiler warnings or the static analyzer. 如果要进行编译时检查,则需要启用更多编译器警告或静态分析器。 However there doesn't seem to be any warning or static analysis check for floating point divide-by-zero errors. 但是,似乎没有任何警告或静态分析检查浮点被零除错误。

Here's a program that produces an analyzer report: 这是一个生成分析报告的程序:

#include <malloc.h>

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

Compiled with clang++ -std=c++11 main.cpp it produces no diagnostics, but compiled with clang++ -std=c++11 --analyze main.cpp it reports the following: 使用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'
}
^

The dead store can also be detected with -Weverything [-Wunused-value], but the leak is only detected by the analyzer. 也可以使用-Weverything [-Wunused-value]检测死存储,但只能通过分析器检测泄漏。

By default full analysis results are written to a plist file. 默认情况下,完整分析结果将写入plist文件。 You can also run the analyzer with the commands: 您还可以使用以下命令运行分析器:

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

To get detailed walk-throughs of detected issues on the standard output or via html display of annotated source code respectively, instead of in a plist. 要分别在标准输出或通过带注释的源代码的html显示中详细了解检测到的问题,而不是在plist中。

Analyzer checks are listed here . 此处列出分析器检查。

Note that to work best the analyzer needs to analyze whole programs, which means it needs to tie into the build system. 请注意,为了最好地工作,分析器需要分析整个程序,这意味着它需要绑定到构建系统。 The usual interface is via an IDE (Xcode) or the scan-build tool with make. 通常的界面是通过IDE(Xcode)或带有make的scan-build工具。 CMake has some clang features such as producing clang JSON compilation database files but I'm not sure off hand if CMake has any built in support for the clang analyzer. CMake有一些铿锵的功能,比如生成clang JSON编译数据库文件,但如果CMake对clang分析器有任何内置支持,我不确定。

So if we look at the documentation in the the Controlling Code Generation it says ( emphasis mine ): 因此,如果我们查看控制代码生成中的文档,它会说( 强调我的 ):

Turn on runtime checks for various forms of undefined or suspicious behavior. 打开运行时检查各种形式的未定义或可疑行为。

This option controls whether Clang adds runtime checks for various forms of undefined or suspicious behavior, and is disabled by default. 此选项控制Clang是否为各种形式的未定义或可疑行为添加运行时检查,并且默认情况下处于禁用状态。 If a check fails, a diagnostic message is produced at runtime explaining the problem . 如果检查失败, 则会在运行时生成诊断消息,说明问题

so these are runtime checks not compile time checks. 所以这些是运行时检查而不是编译时间检查。 So if you used foo in your code then you would see the following output: 因此,如果您在代码中使用了foo ,那么您将看到以下输出:

runtime error: division by zero 运行时错误:除以零

See this example live using -fsanitize=undefined : 使用-fsanitize=undefined查看此示例实时

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

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

it generates two run-time messages: 它会生成两个运行时消息:

main.cpp:6:19: runtime error: shift exponent 100 is too large for 32-bit type 'int' main.cpp:6:19:运行时错误:移位指数100对于32位类型'int'来说太大了

main.cpp:2:36: runtime error: division by zero main.cpp:2:36:运行时错误:除以零

Update 更新

With respect to static checkers, in my answer to A C++ implementation that detects undefined behavior? 关于静态检查器,我在回答A C ++实现时检测到未定义的行为? I mention several tools: STACK , kcc and of course Frama-C . 我提到了几个工具: STACKkcc ,当然还有Frama-C

Apparently clang allows you to use --analyze to run it's static checker but it seems like it may be disabled eventually and the the correct way to run it would be through scan-build . 显然clang允许你使用--analyze来运行它的静态检查器,但似乎它最终可能被禁用,运行它的正确方法是通过scan-build

Also in my self-answered question Why do constant expressions have an exclusion for undefined behavior? 同样在我自我回答的问题中为什么常量表达式排除了未定义的行为? I show how constexprs can be used to catch undefined behavior at compile time. 我展示了如何使用constexprs在编译时捕获未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM