1

我的目标: 使用 clang 静态检查器检测 C/C++ 中的所有缓冲区访问。

我的想法:使用 CheckPosition 让所有内存读/写,然后过滤不相关的项目。

我的问题:但是,当我尝试过滤诸如“int i = 1”“i++”之类的内容时,我被卡住了。

我的解决方案: 过滤此问题的一种方法是使用 isPointerType() 检查变量是否为指针类型。

我的问题: 但我需要先获得 QualType。问题是如何?或者,我还有其他方法可以实现我的目标吗???

我的 Clang 检查器代码如下:

#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm-3.4/llvm/Support/raw_ostream.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"


using namespace clang;
using namespace ento;

namespace {
class BufferAccessChecker : public Checker<check :: Location> {
    //mutable std::unique_ptr<BuiltinBug> BT_access;
    mutable std::unique_ptr<BugType> bugType;

public:

BufferAccessChecker(void) {
    this->bugType.reset(new BugType("buffer access", "chaz analyzer"));
}   
void checkLocation(SVal location, bool isLoad, const Stmt* S, CheckerContext &C) const;

};
}

void BufferAccessChecker::checkLocation(SVal location, bool isLoad, const Stmt* S, CheckerContext &C) const {
if (location.isUndef() || !location.getAs<Loc>())
    return;

const MemRegion *R = location.getAsRegion();
if(!R)
    return;

// if (location.getBaseKind() != SVal::LocKind)
//  return;
// if (location.getSubKind() != loc::MemRegionKind)
//  return;

// const ElementRegion *ER = dyn_cast<ElementRegion>(R);
// if(!ER)
//  return;

ProgramStateRef state = C.getState();
ProgramStateRef notNullState, nullState;
std::tie(notNullState, nullState) = state->assume(L);
//filter some null states
if(isLoad){
    if(!nullState && notNullState){

        if(1){
            ExplodedNode  *loc = C.addTransition();
            BugReport *bug = new BugReport(*this->bugType, 
                "checkLocation: read buffer", loc);
            C.emitReport(bug);
        }
    }
    return;
}else{
    if(!nullState && notNullState){
        ExplodedNode  *loc = C.addTransition();
        BugReport *bug = new BugReport(*this->bugType, 
            "checkLocation: write buffer", loc);
        C.emitReport(bug);
    }
}

}


extern "C"
const char clang_analyzerAPIVersionString[] = CLANG_ANALYZER_API_VERSION_STRING;

extern "C"
void clang_registerCheckers(CheckerRegistry ®istry) {
registry.addChecker <BufferAccessChecker>("alpha.core.BufferAccessChecker", "Checks buffer read/write");
}

测试结果如下:

    clang-3.4 -Xclang -load -Xclang ~/bufferaccesschecker/checker.so -Xclang -analyzer-checker=alpha.core.BufferAccessChecker  -Xclang -analyze -w -c ~/playground/ep2AED/Kmp.c
/home/chaz/playground/ep2AED/Kmp.c:17:14: warning: checkLocation: write buffer
    falha[0] = 0;
    ~~~~~~~~~^~~
/home/chaz/playground/ep2AED/Kmp.c:18:12: warning: checkLocation: read buffer
    while (i<tamanhoPadrao) {
        ^
/home/chaz/playground/ep2AED/Kmp.c:19:18: warning: checkLocation: read buffer
        if (p[i] == p[j]) {
            ~~~~~^~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:20:21: warning: checkLocation: write buffer
            falha[i]= j+1;
            ~~~~~~~~^~~~~
/home/chaz/playground/ep2AED/Kmp.c:26:21: warning: checkLocation: write buffer
            falha[i]=0;
            ~~~~~~~~^~
/home/chaz/playground/ep2AED/Kmp.c:26:22: warning: checkLocation: read buffer
            falha[i]=0;
                    ^
/home/chaz/playground/ep2AED/Kmp.c:27:13: warning: checkLocation: read buffer
            i++;
            ^~~
/home/chaz/playground/ep2AED/Kmp.c:36:18: warning: checkLocation: read buffer
    int* falha = funcaoDeFalha(p);
                ^~~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:38:13: warning: checkLocation: read buffer
    while (*i < tamanhoTexto) {
            ^
/home/chaz/playground/ep2AED/Kmp.c:38:15: warning: checkLocation: read buffer
    while (*i < tamanhoTexto) {
        ~~~^~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:38:17: warning: checkLocation: read buffer
    while (*i < tamanhoTexto) {
                ^~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:39:9: warning: checkLocation: read buffer
        if(texto[*i] == p[*j]){ //match
        ^~
/home/chaz/playground/ep2AED/Kmp.c:39:12: warning: checkLocation: read buffer
        if(texto[*i] == p[*j]){ //match
        ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:39:19: warning: checkLocation: read buffer
        if(texto[*i] == p[*j]){ //match
                ^
/home/chaz/playground/ep2AED/Kmp.c:39:22: warning: checkLocation: read buffer
        if(texto[*i] == p[*j]){ //match
        ~~~~~~~~~~^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:39:28: warning: checkLocation: read buffer
        if(texto[*i] == p[*j]){ //match
                        ^
/home/chaz/playground/ep2AED/Kmp.c:40:17: warning: checkLocation: read buffer
            if(*j == tamanhoPadrao - 1){
                ^
/home/chaz/playground/ep2AED/Kmp.c:40:22: warning: checkLocation: read buffer
            if(*j == tamanhoPadrao - 1){
                    ^~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:41:26: warning: checkLocation: read buffer
                return (*i-*j);
                        ^
/home/chaz/playground/ep2AED/Kmp.c:43:17: warning: checkLocation: read buffer
                (*i)++;
                ^~~~~~
/home/chaz/playground/ep2AED/Kmp.c:43:19: warning: checkLocation: read buffer
                (*i)++;
                ^
/home/chaz/playground/ep2AED/Kmp.c:44:17: warning: checkLocation: read buffer
                (*j)++;
                ^~~~~~
/home/chaz/playground/ep2AED/Kmp.c:44:19: warning: checkLocation: read buffer
                (*j)++;
                ^
/home/chaz/playground/ep2AED/Kmp.c:48:17: warning: checkLocation: read buffer
            if(*j>0){
                ^
/home/chaz/playground/ep2AED/Kmp.c:49:22: warning: checkLocation: read buffer
                (*j) = falha[*j-1];
                ~~~~~^~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:49:31: warning: checkLocation: read buffer
                (*j) = falha[*j-1];
                            ^
/home/chaz/playground/ep2AED/Kmp.c:51:17: warning: checkLocation: read buffer
                (*i)++;
                ^~~~~~
/home/chaz/playground/ep2AED/Kmp.c:51:19: warning: checkLocation: read buffer
                (*i)++;
                ^
/home/chaz/playground/ep2AED/Kmp.c:55:13: warning: checkLocation: read buffer
    return -1;
            ^
/home/chaz/playground/ep2AED/Kmp.c:56:1: warning: checkLocation: read buffer
}
^
/home/chaz/playground/ep2AED/Kmp.c:65:5: warning: checkLocation: read buffer
    int i = KMPMatch(texto, p, &iKmp, &jKmp);
    ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:65:33: warning: checkPreStmt: buffer access
    int i = KMPMatch(texto, p, &iKmp, &jKmp);
                                ^~~~
/home/chaz/playground/ep2AED/Kmp.c:65:40: warning: checkPreStmt: buffer access
    int i = KMPMatch(texto, p, &iKmp, &jKmp);
                                    ^~~~
/home/chaz/playground/ep2AED/Kmp.c:66:5: warning: checkLocation: read buffer
    if(texto[strlen(p)] == ' '){
    ^~
/home/chaz/playground/ep2AED/Kmp.c:66:8: warning: checkLocation: read buffer
    if(texto[strlen(p)] == ' '){
    ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:67:21: warning: checkLocation: write buffer
        resposta[0] = i;
        ~~~~~~~~~~~~^~~
/home/chaz/playground/ep2AED/Kmp.c:67:23: warning: checkLocation: read buffer
        resposta[0] = i;
                    ^
/home/chaz/playground/ep2AED/Kmp.c:68:9: warning: checkLocation: read buffer
        iterador++;
        ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:68:9: warning: checkLocation: read buffer
        iterador++;
        ^~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:71:21: warning: checkLocation: write buffer
        resposta[0] = -1;
        ~~~~~~~~~~~~^~~~
/home/chaz/playground/ep2AED/Kmp.c:72:9: warning: checkLocation: read buffer
        iterador++;
        ^~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:74:5: warning: checkLocation: read buffer
    while (i < strlen(texto) && i != -1){
    ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:74:12: warning: checkLocation: read buffer
    while (i < strlen(texto) && i != -1){
        ^
/home/chaz/playground/ep2AED/Kmp.c:74:14: warning: checkLocation: read buffer
    while (i < strlen(texto) && i != -1){
        ~~^~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:74:16: warning: checkLocation: read buffer
    while (i < strlen(texto) && i != -1){
            ^~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:74:23: warning: checkLocation: read buffer
    while (i < strlen(texto) && i != -1){
                    ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:74:30: warning: checkLocation: read buffer
    while (i < strlen(texto) && i != -1){
        ~~~~~~~~~~~~~~~~~~^~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:74:33: warning: checkLocation: read buffer
    while (i < strlen(texto) && i != -1){
                                ^
/home/chaz/playground/ep2AED/Kmp.c:75:9: warning: checkLocation: read buffer
        i = KMPMatch(texto, p , &iKmp,&jKmp);
        ^
/home/chaz/playground/ep2AED/Kmp.c:75:11: warning: checkLocation: read buffer
        i = KMPMatch(texto, p , &iKmp,&jKmp);
        ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:75:13: warning: checkLocation: read buffer
        i = KMPMatch(texto, p , &iKmp,&jKmp);
            ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:75:22: warning: checkLocation: read buffer
        i = KMPMatch(texto, p , &iKmp,&jKmp);
                    ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:75:34: warning: checkLocation: read buffer
        i = KMPMatch(texto, p , &iKmp,&jKmp);
                                ^~~~
/home/chaz/playground/ep2AED/Kmp.c:75:34: warning: checkPreStmt: buffer access
        i = KMPMatch(texto, p , &iKmp,&jKmp);
                                ^~~~
/home/chaz/playground/ep2AED/Kmp.c:75:40: warning: checkLocation: read buffer
        i = KMPMatch(texto, p , &iKmp,&jKmp);
                                    ^~~~
/home/chaz/playground/ep2AED/Kmp.c:75:40: warning: checkPreStmt: buffer access
        i = KMPMatch(texto, p , &iKmp,&jKmp);
                                    ^~~~
/home/chaz/playground/ep2AED/Kmp.c:76:9: warning: checkLocation: read buffer
        if(texto[i-1] == ' '){
        ^~
/home/chaz/playground/ep2AED/Kmp.c:76:12: warning: checkLocation: read buffer
        if(texto[i-1] == ' '){
        ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:76:18: warning: checkLocation: read buffer
        if(texto[i-1] == ' '){
                ^
/home/chaz/playground/ep2AED/Kmp.c:78:32: warning: checkLocation: read buffer
            resposta[iterador] = i;
            ~~~~~~~~~~~~~~~~~~~^~~
/home/chaz/playground/ep2AED/Kmp.c:78:32: warning: checkLocation: write buffer
            resposta[iterador] = i;
            ~~~~~~~~~~~~~~~~~~~^~~
/home/chaz/playground/ep2AED/Kmp.c:79:13: warning: checkLocation: read buffer
            iterador++;
            ^~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:82:6: warning: checkLocation: read buffer
    *controle = iterador;
    ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:82:15: warning: checkLocation: read buffer
    *controle = iterador;
    ~~~~~~~~~~^~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:82:17: warning: checkLocation: read buffer
    *controle = iterador;
                ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:83:5: warning: checkLocation: read buffer
    return resposta;
    ^~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:83:12: warning: checkLocation: read buffer
    return resposta;
        ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:84:1: warning: checkLocation: read buffer
}
^
/home/chaz/playground/ep2AED/Kmp.c:92:15: warning: checkLocation: read buffer
        while(i < *controle){
            ^
/home/chaz/playground/ep2AED/Kmp.c:92:20: warning: checkLocation: read buffer
        while(i < *controle){
                ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:93:16: warning: checkLocation: read buffer
            if(resposta[0] == -1)//nao existe a palavra
            ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:93:16: warning: checkLocation: read buffer
            if(resposta[0] == -1)//nao existe a palavra
            ^~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:94:39: warning: checkLocation: read buffer
                printf("%d", resposta[0]);
                                    ^
/home/chaz/playground/ep2AED/Kmp.c:95:37: warning: checkLocation: read buffer
            else  if(resposta[i] != -1){
                                    ^~
/home/chaz/playground/ep2AED/Kmp.c:96:40: warning: checkLocation: read buffer
                printf("%d ", resposta[i]);
                                    ^
/home/chaz/playground/ep2AED/Kmp.c:98:13: warning: checkLocation: read buffer
            i++;
            ^~~
/home/chaz/playground/ep2AED/Kmp.c:99:10: warning: checkLocation: read buffer
        }printf("\n");
        ^~~~~~
/home/chaz/playground/ep2AED/Kmp.c:102:9: warning: checkLocation: read buffer
        while(palavras) {
        ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:102:15: warning: checkLocation: read buffer
        while(palavras) {
            ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:104:13: warning: checkLocation: read buffer
            int *resposta = ChamaKMP(texto, palavras,numeroDePadroes, controle);
            ^~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:104:29: warning: checkLocation: read buffer
            int *resposta = ChamaKMP(texto, palavras,numeroDePadroes, controle);
                            ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:104:29: warning: checkLocation: read buffer
            int *resposta = ChamaKMP(texto, palavras,numeroDePadroes, controle);
                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:104:38: warning: checkLocation: read buffer
            int *resposta = ChamaKMP(texto, palavras,numeroDePadroes, controle);
                                    ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:104:45: warning: checkLocation: read buffer
            int *resposta = ChamaKMP(texto, palavras,numeroDePadroes, controle);
                                            ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:104:54: warning: checkLocation: read buffer
            int *resposta = ChamaKMP(texto, palavras,numeroDePadroes, controle);
                                                    ^~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:104:71: warning: checkLocation: read buffer
            int *resposta = ChamaKMP(texto, palavras,numeroDePadroes, controle);
                                                                    ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:105:13: warning: checkLocation: read buffer
            while(i < *controle){
            ^~~~~
/home/chaz/playground/ep2AED/Kmp.c:105:19: warning: checkLocation: read buffer
            while(i < *controle){
                ^
/home/chaz/playground/ep2AED/Kmp.c:105:24: warning: checkLocation: read buffer
            while(i < *controle){
                    ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:106:17: warning: checkLocation: read buffer
                if(resposta[0] == -1)//nao existe a palavra
                ^~
/home/chaz/playground/ep2AED/Kmp.c:106:20: warning: checkLocation: read buffer
                if(resposta[0] == -1)//nao existe a palavra
                ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:106:32: warning: checkLocation: read buffer
                if(resposta[0] == -1)//nao existe a palavra
                ~~~~~~~~~~~~^~~~~
/home/chaz/playground/ep2AED/Kmp.c:107:21: warning: checkLocation: read buffer
                    printf("%d", resposta[0]);
                    ^~~~~~
/home/chaz/playground/ep2AED/Kmp.c:107:21: warning: checkLocation: read buffer
                    printf("%d", resposta[0]);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:107:34: warning: checkLocation: read buffer
                    printf("%d", resposta[0]);
                                ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:108:25: warning: checkLocation: read buffer
                else if(resposta[i] != -1){
                        ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:108:34: warning: checkLocation: read buffer
                else if(resposta[i] != -1){
                                ^
/home/chaz/playground/ep2AED/Kmp.c:108:37: warning: checkLocation: read buffer
                else if(resposta[i] != -1){
                        ~~~~~~~~~~~~^~~~~
/home/chaz/playground/ep2AED/Kmp.c:109:21: warning: checkLocation: read buffer
                    printf("%d ", resposta[i]);
                    ^~~~~~
/home/chaz/playground/ep2AED/Kmp.c:109:21: warning: checkLocation: read buffer
                    printf("%d ", resposta[i]);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:109:35: warning: checkLocation: read buffer
                    printf("%d ", resposta[i]);
                                ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:109:44: warning: checkLocation: read buffer
                    printf("%d ", resposta[i]);
                                        ^
/home/chaz/playground/ep2AED/Kmp.c:111:17: warning: checkLocation: read buffer
                i++;
                ^
/home/chaz/playground/ep2AED/Kmp.c:111:17: warning: checkLocation: read buffer
                i++;
                ^~~
/home/chaz/playground/ep2AED/Kmp.c:112:14: warning: checkLocation: read buffer
            }printf("\n");
            ^~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:112:21: warning: checkLocation: read buffer
            }printf("\n");
                    ^~~~
/home/chaz/playground/ep2AED/Kmp.c:113:13: warning: checkLocation: read buffer
            i = 0;
            ^
/home/chaz/playground/ep2AED/Kmp.c:113:15: warning: checkLocation: read buffer
            i = 0;
            ~~^~~
/home/chaz/playground/ep2AED/Kmp.c:114:22: warning: checkLocation: read buffer
            palavras = strtok(NULL, " ");
            ~~~~~~~~~^~~~~~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:114:24: warning: checkLocation: read buffer
            palavras = strtok(NULL, " ");
                    ^~~~~~~~~~~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:117:1: warning: checkLocation: read buffer
}

以下是选择的一些不满意的测试结果:

应过滤 int 类型变量

/home/chaz/playground/ep2AED/Kmp.c:27:13: warning: checkLocation: read buffer
            i++;

返回表达式应该被过滤

/home/chaz/playground/ep2AED/Kmp.c:55:13: warning: checkLocation: read buffer
    return -1;
/home/chaz/playground/ep2AED/Kmp.c:56:1: warning: checkLocation: read buffer
}

这出现了两次

/home/chaz/playground/ep2AED/Kmp.c:68:9: warning: checkLocation: read buffer
        iterador++;
        ^~~~~~~~
/home/chaz/playground/ep2AED/Kmp.c:68:9: warning: checkLocation: read buffer
        iterador++;
        ^~~~~~~~~~

顺便说一句,测试代码在这里: https ://github.com/lucascapalbo/ep2AED

测试命令在这里:

clang-3.4 -Xclang -load -Xclang ~/bufferaccesschecker/checker.so -Xclang -analyzer-checker=alpha.core.BufferAccessChecker  -Xclang -analyze -w -c ~/playground/ep2AED/Kmp.c
4

1 回答 1

0

在 Artem Dergachev 的帮助下,这个问题得到了解决。超级感谢他。

解决思路如下:

(1) dump stmt byStmt.dump()就可以看到 ast 树

(2)根据ast树,可以将stmt dyn_cast成不同的expr类型。然后你可以通过 expr.getType() 得到 QualType。然后,我们可以通过 isAnyPointerType() 过滤指针类型

Clang 并不难,但可能会让初学者感到困惑(尤其是对我而言)

你应该做的是仔细阅读这些材料。

https://github.com/haoNoQ/clang-analyzer-guide/releases/download/v0.1/clang-analyzer-guide-v0.1.pdf
http://clang-analyzer.llvm.org/checker_dev_manual.html

当您开始编写检查器时,您总是可以在这里检查不同且令人困惑的类,而不是阅读源代码。

https://clang.llvm.org/doxygen/

希望这可以帮助!

于 2018-10-05T02:26:33.477 回答