#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" #include using namespace clang; using namespace ento; using namespace std; #include template string toString(const T& obj) { stringstream stream; stream << obj; return stream.str(); } #include #include #include #include // trim from start static inline std::string <rim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); return s; } // trim from end static inline std::string &rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); return s; } // trim from both ends static inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); } 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); } } }*/ vector labels; ConstraintMatrix T; while (cin.good()) { string line; getline(cin, line); trim(line); if (line.length() == 0) continue; map row; size_t neg_sign_index = line.find('-'); if (neg_sign_index == string::npos) { row[line] = 1; labels.push_back(line); } else if (neg_sign_index == 0) { row[line.substr(1)] = -1; labels.push_back('-'+line.substr(1)); } else { string left = line.substr(0, neg_sign_index); string right = line.substr(neg_sign_index+1); trim(left); trim(right); if (left != right) { row[left] = 1; row[right] = -1; } labels.push_back(left + '-' + right); } T.push_back(row); } 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(); }