静态分析工具Clang Static Analyzer (5) Clangsa

您所在的位置:网站首页 codechecker编译 静态分析工具Clang Static Analyzer (5) Clangsa

静态分析工具Clang Static Analyzer (5) Clangsa

2024-07-08 07:16| 来源: 网络整理| 查看: 265

​​想了解更多关于开源的内容,请访问:​​

​​51CTO 开源基础软件社区​​

​​https://ost.51cto.com​​

接着本系列之前的文章,补充下CodeChecker的部分用法。使用命令CodeChecker analyzers可以查看当前支持的静态分析检查器analyzers。如果安装了Cppcheck就会展示出来,clangsa和Clang-tidy是LLVM Clang编译工具链提供的静态分析检查器。

zhushangyuan@DESKTOP-RPE9R4O:~/CSA$ CodeChecker analyzers cppcheckzhushangyuan@DESKTOP-RPE9R4O:~/CSA$ export PATH=~/openharmony/prebuilts/clang/ohos/linux-x86_64/llvm/bin:$PATHzhushangyuan@DESKTOP-RPE9R4O:~/CSA$ CodeChecker analyzers clangsa cppcheck clang-tidy

在使用CodeChecker静态分析时,可以使用选项[--analyzers ANALYZER [ANALYZER ...]指定只使能部分分析器,这些ANALYZER可以是clangsa、cppcheck、clang-tidy。如下:

CodeChecker analyze --analyzers clangsa compile_commands.json -o ./reports

系列文章中的前几篇中,已经到了Cppcheck和Clang-tidy这2个静态检查分析器,本文快速介绍下clangsa静态检查分析器。

1、clangsa介绍

前面系列文章介绍了Clang Static Analyzer,知道Clang 静态分析器CSA是一个源代码分析工具,可查找 C、C++ 和 Objective-C 程序的bugs。Clang Static Analyzer可以理解提供了两部分内容,一部分是CSA工具,比如scan-build、CodeChecker,还有一部分是clangsa,虽然是Clang Static Analyzer的缩写,但是指的是Clang Static Analyzer的静态检查分析器,定义了一些的代码缺陷检查规则。详细可以参考链接https://clang.llvm.org/docs/ClangStaticAnalyzer.html,除了支持的检查器,还有用户文档和开发文档,用于支持定制自己的检查器。

本文主要学习下clangsa支持的检查器Available Checkers。

clangsa、cppcheck、clang-tidy属于分析器analyzer,每个分析器定义了自己的一套检查器“checkers”。检查器还会通过分组进行管理。clangsa分析器的检查器分为三组,分别为:

Default Checkers 默认检查器,可以发现安全和API使用缺陷,死代码和其他逻辑错误。。请参阅下面的默认检查器列表。Experimental Checkers 实验检查器也称为alpha checkers,处于开发过程中,默认关闭。可能会崩溃,也可能产生较多的误报。Debug Checkers 调测检查器被分析器开发者用作调测目的。2、Default Checkers 默认检查器

默认检查器分为如下几组。只关注C、C++相关的检查器,osx、Fuchsia、nullability、WebKit可以自行按需了解。

core 核心语言特性,通用的检查器cplusplus C++语言检查器deadcode 死代码检查器nullability Objective-C空指针传递和解引用检查器optin 可移植、性能或编程风格相关的检查器security 安全相关检查器unix POSIX/Unix检查器osx macOS检查器Fuchsia Fuchsia操作系统相关的检查器。Fuchsia是Google开发的一款开源操作系统。WebKit WebKit相关检查器。WebKit是开源Web浏览器引擎。(1)core检查器

core检查器关注语言的核心特性,包含通用目的的检查器,例如除零错误,空指针解引用,使用未初始化的值等。这些检查器需要一直开启,其他检查器依赖这些核心检查器。

core.CallAndMessage (C, C++, ObjC)检查函数调用的逻辑错误,Objective-C消息表达错误,例如,未初始化参数,空函数指针等。适用于C, C++, ObjC等编程语言。//Cvoid test() { void (*foo)(void); foo = 0; foo(); // warn: function pointer is null 函数指针为空 } // C++ class C { public: void f(); }; void test() { C *pc; pc->f(); // warn: object pointer is uninitialized 对象指针未初始化 } // C++ class C { public: void f(); }; void test() { C *pc = 0; pc->f(); // warn: object pointer is null 对象指针为空 } // Objective-C......core.DivideZero (C, C++, ObjC)检查是否存在除零错误。void test(int z) {if (z == 0) int x = 1 / z; // warn 除零错误}void test() {int x = 1;int y = x % 0; // warn 除零错误}core.NullDereference (C, C++, ObjC)检查空指针的解引用错误。SuppressAddressSpaces选项会屏蔽带地址空间的空指针解引用告警。可以使用选项-analyzer-config core.NullDereference:SuppressAddressSpaces=false来关注该SuppressAddressSpaces。默认是开启的。// C void test(int *p) { if (p) return;

int x = p[0]; // warn }

// Cvoid test(int *p) { if (!p) *p = 0; // warn}

// C++class C {public: int x;};

void test() { C *pc = 0; int k = pc->x; // warn}

// Objective-C......

core.StackAddressEscape ©检查堆栈越界,在一个函数内部声明的局部变量存储在栈空间上,不能把该变量的地址传递到函数外部。char const *p;

void test() { char const str[] = "string"; p = str; // warn StackAddressEscape告警}

void* test() { return __builtin_alloca(12); // warn StackAddressEscape告警}

void test() { static int *x; int y; x = &y; // warn StackAddressEscape告警}

core.UndefinedBinaryOperatorResult ©检查二元表达式中的未定义的值。void test() {int x;int y = x + 1; // warn: left operand is garbage}core.VLASize ©检查变长数组(Variable Length Arrays,VLA)的长度未定义或者零值。void test() { int x; int vla1[x]; // warn: garbage as size}

void test() { int x = 0; int vla2[x]; // warn: zero size}

core.uninitialized.ArraySubscript ©检查未初始化的值用作数组下标。void test() { int i, a[10]; int x = a[i]; // warn: array subscript is undefined}core.uninitialized.Assign ©检查使用未初始化的值进行赋值。void test() { int x; x |= 1; // warn: left expression is uninitialized 左表达式未初始化}core.uninitialized.Branch ©

检查未初始化的值用于条件分支。

void test() { int x; if (x) // warn return;}core.uninitialized.CapturedBlockVariable ©检查代码块捕获未初始化的值。void test() { int x; ^{ int y = x; }(); // warn}core.uninitialized.UndefReturn ©检查未初始化的值传递到外层函数。int test() { int x; return x; // warn}(2)cplusplus检查器

C++语言相关的检查器。

cplusplus.InnerPointer (C++)检查在re/deallocation之后使用的C容器的内部指针。C标准库中的许多容器方法会让指向容器元素的引用无效,包含实际引用,迭代器,原生指针(raw pointers)。使用无效的引用会引起未定义行为,这通常是C++中内存错误的源头,也是该检查致力于检查出来的代码缺陷。该检查器只是适合std::string对象,不能识别出复杂的用法,比如传递std::string_view这样的unowned指针。void deref_after_assignment() { std::string s = "llvm"; const char *c = s.data(); // note: pointer to inner buffer of 'std::string' obtained here s = "clang"; // note: inner buffer of 'std::string' reallocated by call to 'operator=' consume(c); // warn: inner pointer of container used after re/deallocation}

const char *return_temp(int x) { return std::to_string(x).c_str(); // warn: inner pointer of container used after re/deallocation // note: pointer to inner buffer of 'std::string' obtained here // note: inner buffer of 'std::string' deallocated by call to destructor}

cplusplus.NewDelete (C++)检查重复释放double-free和释放后使用UAF等内存问题。追踪被new/delete管理的内存。void f(int *p);void testUseMiddleArgAfterDelete(int *p) { delete p; f(p); // warn: use after free 释放后使用}

class SomeClass {public: void f();};

void test() { SomeClass *c = new SomeClass; delete c; c->f(); // warn: use after free 释放后使用}

void test() { int *p = (int *)__builtin_alloca(sizeof(int)); delete p; // warn: deleting memory allocated by alloca // 释放使用alloca申请的内存}

void test() { int *p = new int; delete p; delete p; // warn: attempt to free released 重复释放内存}

void test() { int i; delete &i; // warn: delete address of local 释放局部变量的栈内存}

void test() { int *p = new int[1]; delete[] (++p); // warn: argument to 'delete[]' is offset by 4 bytes // from the start of memory allocated by 'new[]' // 传递给'delete[]'的参数相对'new[]'申请的内存开始地址进行了4字节偏移 // 释放的不是申请的内存。}

cplusplus.NewDeleteLeaks (C++)检查内存泄露memory leaks. 追踪new/delete管理的内存。void test() { int *p = new int;} // warn 申请未释放cplusplus.PlacementNewChecker (C++)Check if default placement new is provided with pointers to sufficient storage capacity. 检查缺省的定位new(placement new)指针操作,有足够的存储能力。#include

void f() { short s; long *lp = ::new (&s) long; // warn}

cplusplus.SelfAssignment (C++)检查C++的自赋值的copy 和 move赋值操作。cplusplus.StringChecker (C++)检查 std::string 操作。检查从std::string对象构造的cstring是否为空NULL。如果检查器不能推断出该指针为空,会假设其非空,用于满足构造。

该检查器可以检查SEI CERT C++编程规则STR51-CPP。不要从空指针创建std::string对象。

#include

void f(const char *p) { if (!p) { std::string msg(p); // warn: The parameter must not be null }}

(3)deadcode检查器deadcode.DeadStores ©检查存储在变量里的值后续未被使用。void test() {int x;x = 1; // warn}

WarnForDeadNestedAssignments选项会使能检查器来检测嵌套的无用的赋值代码,可以使用选项-analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false来关闭该选项。WarnForDeadNestedAssignments`选项默认开启。

会对这样的代码进行告警,例如: if ((y = make_int())) { }。

(4)security检查器security.FloatLoopCounter ©浮点数作为循环变量 (CERT: FLP30-C, FLP30-CPP).void test() { for (float x = 0.1f; x b) return a; return b;}

int maxClone(int x, int y) { // similar code here log(); if (x > y) return x; return y;}

(2)alpha.core检查器

简单看一个,其他更多检查器,可以自行访问官网文档https://clang.llvm.org/docs/analyzer/checkers.html#alpha-core。

alpha.core.C11Lock类似alpha.unix.PthreadLock,检查互斥锁的mtx_t mutexeslocking/unlocking的上锁和解锁。mtx_t mtx1;

void bad1(void){ mtx_lock(&mtx1); mtx_lock(&mtx1); // warn: This lock has already been acquired}

​​想了解更多关于开源的内容,请访问:​​

​​51CTO 开源基础软件社区​​

​​https://ost.51cto.com​​



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3