相关知识

敏感性分析和过程内(间)分析等,见[编译基本知识点汇总]

CTU分析

CTU:Cross Translation Unit

背景

一个.c.cpp源文件可以被生成为一个.ast文件。简单来说,一个.ast文件就是一个 TU(Translation Unit)
CTU分析 指的是:在分析一个TU时,由于某些被调用的函数的定义没有在本TU内,必须去别的TU找对应的函数定义,才能完成完整的过程间分析(否则只分析本TU内的函数调用,不是完整的过程间分析)。
早期的Clang静态分析是不支持CTU分析的。

  • 2017年,欧洲LLVM开发者大会上,Ericsson提出了CTU的设计与实现
  • 2018年,LLVM正式接收了这个实现并将其并入了Clang的Release版本中

CTU基本原理

CTU分析的核心就是:
在生成CallGraph时,先在本TU查找被调用函数的定义,若没找到,根据全局函数签名Map去动态查找被调用的函数。

基本流程同非CTU的分析是一样的:

  1. 处理所有的顶层函数
  2. 处理整个TU:生成CallGraph、通过Engine进行分析等

CTU调用过程图

CTU测试

对于以下源文件:
a.h

1
int foo(int len, int x);

a.c

1
2
3
4
5
6
7
8
#include "a.h"

int foo(int len, int x) {
int j = 0;
if (len < 10)
j = 42 / j;
return j;
}

b.h

1
int bar(int x);

b.c

1
2
3
4
5
6
#include "b.h"
#include "a.h"

int bar(int x) {
return foo(x, x);
}

main.c

1
2
3
4
5
6
#include "b.h"

int main() {
int x = bar(66);
int y = 4 / x;
}

Makefile

1
2
main: main.c
gcc -o main a.c b.c main.c

前期准备

compilation_database.json

这个文件包含程序的编译信息,在分析的时候会被CSA使用

1
2
$ bear make
gcc -o main a.c b.c main.c

externalFnMap.txt

externalFnMap.txt是一个包含待分析程序中所有函数签名的文件,在跨TU分析时CSA将动态地根据这个文件的内容,将函数签名作为key,去加载这个签名所在的.ast文件,从而加载到这个函数签名对应的函数定义(value)。

  1. 使用clang-func-mapping
1
2
3
4
$ clang-func-mapping a.c b.c main.c
c:@F@foo /home/katherine/LLVM/testclang/include/a.c
c:@F@bar /home/katherine/LLVM/testclang/include/b.c
c:@F@main /home/katherine/LLVM/testclang/include/main.c
  1. clang-func-mapping的输出结果重定向到externalFnMap.txt文件中:
1
$ clang-func-mapping a.c b.c main.c > externalFnMap.txt
  1. externalFnMap.txt文件中的.c后缀修改为.c.ast后缀:
1
2
3
c:@F@foo /home/katherine/LLVM/testclang/include/a.c.ast
c:@F@bar /home/katherine/LLVM/testclang/include/b.c.ast
c:@F@main /home/katherine/LLVM/testclang/include/main.c.ast
  1. 生成与externalFnMap.txt文件中路径相同的ast文件

[说明]:
以上操作将使用panda适配,直接panda -A,将生成ast目录树(包含.ast文件),及对应的externalFnMap.txt

CTU分析

基本命令

1
$ clang -cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyze-function=main -analyzer-config experimental-enable-naive-ctu-analysis=true -analyzer-config ctu-dir=./ -o ./bugs
  • -cc1
  • -analyze:启用CSA
  • -analyze-checher:指定checker
  • -analyze-function:指定需要分析的函数,如果不指定则全局分析
  • -analyze-config:CSA配置
    • experimental-enable-naive-ctu-analysis: 是否启用ctu分析,默认false
    • ctu-dir: ctu分析的基本目录,加上.ast文件的相对路径,才是最终.ast文件的绝对路径
    • ctu-index-name: 函数签名字典文件的名称,默认“externalFnMap.txt”
  • -o 输出报告目录

关于 -analyze-config 你可以这样两种写法:

  1. 每个子参数前加一个 -analyze-config 参数,分开写:
1
-analyzer-config experimental-enable-naive-ctu-analysis=true -analyzer-config ctu-dir=./
  1. 只写一个 -analyze-config 参数,所有
1
-analyzer-config experimental-enable-naive-ctu-analysis=true,ctu-dir=./

注:
像这样将所有待分析的文件(a.c b.c main.c)全部输入,会出现一个问题:生成重复的bug待解决

终端输出

在执行完基本命令后,对于本测试代码,终端将输出如下结果:

1
2
3
4
5
6
7
8
9
10
a.c:6:10: warning: Division by zero
j = 42 / j;
~~~^~~
/home/katherine/LLVM/testclang/include/a.c:6:10: warning: Division by zero
j = 42 / j;
~~~^~~
main.c:5:12: warning: Division by zero
int y = 4 / x;
~~^~~
3 warnings generated.

报告

本例分析命令中,我们将Bug文件夹指定为当前目录下的bugs文件夹。进入文件夹,可以看到所有的bug报告:

1
2
3
4
5
$ cd bugs
$ ls -al
-rw-r--r-- 1 katherine katherine 11872 3月 24 18:43 report-115cb6.html
-rw-r--r-- 1 katherine katherine 17301 3月 24 18:43 report-2c5579.html
-rw-r--r-- 1 katherine katherine 13924 3月 24 18:43 report-987a82.html

错误报告