#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 template string toString(const T& obj) { stringstream stream; stream << obj; return stream.str(); } namespace { class IntervalTest: public Checker { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { if (IntervalAnalysis *a = mgr.getAnalysis(D)) { CFG* cfg = mgr.getCFG(D); set variables; if (const FunctionDecl* func = dyn_cast(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(); const Stmt* stmt = cfg_stmt->getStmt(); if (stmt->getStmtClass() == Stmt::BinaryOperatorClass) { const BinaryOperator* binop = static_cast(stmt); if (binop->isAssignmentOp()) { const Expr* left = binop->getLHS()->IgnoreParenCasts(); if (left->getStmtClass() == Stmt::DeclRefExprClass) { variables.insert(static_cast(left)->getNameInfo().getAsString()); } } } else if (stmt->getStmtClass() == Stmt::DeclStmtClass) { const DeclStmt* decl_stmt = static_cast(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(*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 labels; ConstraintMatrix T; set::iterator end = variables.end(); for (set::iterator it = variables.begin(); it != end; ++it) { map pos_row; pos_row[*it] = 1; T.push_back(pos_row); labels.push_back(*it); map neg_row; neg_row[*it] = -1; T.push_back(neg_row); labels.push_back("-" + *it); for (set::iterator jt = variables.begin(); jt != end; ++jt) { if (it != jt) { map diff_row; diff_row[*it] = 1; diff_row[*jt] = -1; T.push_back(diff_row); labels.push_back(*it + " - " + *jt); } } } map > result = a->runOnAllBlocks(*D, T); for (map >::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(); }