summaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Checkers/IntervalTest.cpp
blob: c1e0273c233d8bd240f98cca243215bf49494869 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/Analysis/Analyses/Interval.h"
#include "clang/Analysis/CallGraph.h"
#include "llvm/Support/Process.h"

using namespace clang;
using namespace ento;
using namespace std;

#include <sstream>
template<typename T>
string toString(const T& obj) {
  stringstream stream;
  stream << obj;
  return stream.str();
}

namespace {
class IntervalTest: public Checker<check::ASTCodeBody> {
public:
  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
                        BugReporter &BR) const {
    if (IntervalAnalysis *a = mgr.getAnalysis<IntervalAnalysis>(D)) {
      CFG* cfg = mgr.getCFG(D);

      set<string> variables;

      if (const FunctionDecl* func = dyn_cast<const FunctionDecl>(D)) {
        for (unsigned int i = func->getNumParams(); i > 0; i--) {
          variables.insert(func->getParamDecl(i-1)->getNameAsString());
        }
      }
      for (CFG::iterator
             it = cfg->begin(),
             ei = cfg->end();
           it != ei;
           ++it) {
        for (CFGBlock::iterator
               block_it = (*it)->begin(),
               block_end = (*it)->end();
             block_it != block_end;
             block_it++) {
          const CFGStmt* cfg_stmt = block_it->getAs<CFGStmt>();
          const Stmt* stmt = cfg_stmt->getStmt();
          if (stmt->getStmtClass() == Stmt::BinaryOperatorClass) {
            const BinaryOperator* binop = static_cast<const BinaryOperator*>(stmt);
            if (binop->isAssignmentOp()) {
              const Expr* left = binop->getLHS()->IgnoreParenCasts();
              if (left->getStmtClass() == Stmt::DeclRefExprClass) {
                variables.insert(static_cast<const DeclRefExpr*>(left)->getNameInfo().getAsString());
              }
            }
          } else if (stmt->getStmtClass() == Stmt::DeclStmtClass) {
            const DeclStmt* decl_stmt = static_cast<const DeclStmt*>(stmt);
            for (DeclStmt::const_decl_iterator jt = decl_stmt->decl_begin(),
                   ej = decl_stmt->decl_end();
                 jt != ej;
                 ++jt) {
              if ((*jt)->getKind() == Decl::Var) {
                const VarDecl* decl = static_cast<const VarDecl*>(*jt);
                variables.insert(decl->getNameAsString());
                jt++;
                if (jt != ej) {
                  llvm::errs() << "Only the first declaration in a multi-declaration statement is used.\n";
                }
                break; // only take the first one, for now
              }
            }
          }
        }
      }



      vector<string> labels;
      ConstraintMatrix T;
      set<string>::iterator end = variables.end();
      for (set<string>::iterator it = variables.begin();
           it != end;
           ++it) {
        map<string,int> pos_row;
        pos_row[*it] = 1;
        T.push_back(pos_row);
        labels.push_back(*it);

        map<string,int> neg_row;
        neg_row[*it] = -1;
        T.push_back(neg_row);
        labels.push_back("-" + *it);

        for (set<string>::iterator jt = variables.begin();
             jt != end;
             ++jt) {
          if (it != jt) {
            map<string,int> diff_row;
            diff_row[*it] = 1;
            diff_row[*jt] = -1;
            T.push_back(diff_row);
            labels.push_back(*it + " - " + *jt);
          }
        }
      }

      map<CFGBlock*,vector<ZBar> > result = a->runOnAllBlocks(*D, T);

      for (map<CFGBlock*,vector<ZBar> >::iterator
             it = result.begin(),
             ei = result.end();
           it != ei;
           ++it) {
        llvm::errs() << "Block " << toString(it->first->getBlockID()) << ": \n";
        for (unsigned int i = 0; i < T.size(); ++i) {
          llvm::errs() << "\t" << labels[i] << " <= " << toString(it->second[i]) << "\n";
        }
      }
    }
  }
};
}

void ento::registerIntervalTestChecker(CheckerManager &mgr) {
  mgr.registerChecker<IntervalTest>();
}