My target: detect all buffer access in C/C++ by using clang static checker.
My idea: use CheckPosition to get all memory read/write and then filter unrelated items.
My problem: However, I got stuck when I try to filter something like "int i = 1" "i++".
My solution: One way to filter this is to check whether the variable is pointer type or not by using isPointerType().
My question: But I need to get QualType first. The question is how? Or, do I have other ways to achieve my target???
My Clang Checker Code is as below:
#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");
}
The test result is as below:
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
}
Here are some unsatisfied test results selected:
int type variable should be filtered
/home/chaz/playground/ep2AED/Kmp.c:27:13: warning: checkLocation: read buffer
i++;
return expression should be filtered
/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
}
This arises twice
/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++;
^~~~~~~~~~
BTW, the test code is here: https://github.com/lucascapalbo/ep2AED
the test command is here:
clang-3.4 -Xclang -load -Xclang ~/bufferaccesschecker/checker.so -Xclang -analyzer-checker=alpha.core.BufferAccessChecker -Xclang -analyze -w -c ~/playground/ep2AED/Kmp.c
The problem was solved with the help of Artem Dergachev. Super thanks to him.
The solution idea is as below:
(1) dump the stmt by
Stmt.dump()and you can see the ast tree(2) according to the ast tree, you can dyn_cast stmt into different expr type. And then you can get QualType by expr.getType(). Then, we can filter the pointer type by isAnyPointerType()
Clang is not that hard but may be confusing to beginners (especially for me)
What you should do is to read those mateial carefully.
When you begin to code the checker, you can always check different and confusing classes here rather than read the source code.
Hope this helps!