aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/BugReporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis/BugReporter.cpp')
-rw-r--r--lib/Analysis/BugReporter.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
new file mode 100644
index 0000000000..2ae0960206
--- /dev/null
+++ b/lib/Analysis/BugReporter.cpp
@@ -0,0 +1,262 @@
+// BugReporter.cpp - Generate PathDiagnostics for Bugs ------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines BugReporter, a utility class for generating
+// PathDiagnostics for analyses based on GRSimpleVals.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CFG.h"
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include <sstream>
+
+using namespace clang;
+
+BugReporter::~BugReporter() {}
+
+static inline Stmt* GetStmt(const ProgramPoint& P) {
+ if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
+ return PS->getStmt();
+ }
+ else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
+ return BE->getSrc()->getTerminator();
+ }
+ else if (const BlockEntrance* BE = dyn_cast<BlockEntrance>(&P)) {
+ return BE->getFirstStmt();
+ }
+
+ assert (false && "Unsupported ProgramPoint.");
+ return NULL;
+}
+
+
+PathDiagnosticPiece*
+BugDescription::getEndPath(ASTContext& Ctx,
+ ExplodedNode<ValueState> *N) const {
+
+ Stmt* S = GetStmt(N->getLocation());
+
+ if (!S)
+ return NULL;
+
+ FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager());
+ PathDiagnosticPiece* P = new PathDiagnosticPiece(L, getDescription());
+
+ if (Expr* E = dyn_cast<Expr>(S))
+ P->addRange(E->getSourceRange());
+
+ return P;
+}
+
+void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
+ const BugDescription& B,
+ ExplodedGraph<GRExprEngine>& G,
+ ExplodedNode<ValueState>* N) {
+
+ PD.push_back(B.getEndPath(Ctx, N));
+
+ SourceManager& SMgr = Ctx.getSourceManager();
+
+
+ llvm::OwningPtr<ExplodedGraph<GRExprEngine> > GTrim(G.Trim(&N, &N+1));
+
+ while (!N->pred_empty()) {
+
+ ExplodedNode<ValueState>* LastNode = N;
+ N = *(N->pred_begin());
+
+ ProgramPoint P = N->getLocation();
+
+ if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
+
+ CFGBlock* Src = BE->getSrc();
+ CFGBlock* Dst = BE->getDst();
+
+ Stmt* T = Src->getTerminator();
+
+ if (!T)
+ continue;
+
+ FullSourceLoc L(T->getLocStart(), SMgr);
+
+ switch (T->getStmtClass()) {
+ default:
+ break;
+
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass: {
+
+ Stmt* S = GetStmt(LastNode->getLocation());
+
+ if (!S)
+ continue;
+
+ std::ostringstream os;
+
+ os << "Control jumps to line "
+ << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
+
+ PD.push_front(new PathDiagnosticPiece(L, os.str()));
+ break;
+ }
+
+ case Stmt::SwitchStmtClass: {
+
+ // Figure out what case arm we took.
+
+ Stmt* S = Dst->getLabel();
+
+ if (!S)
+ continue;
+
+ std::ostringstream os;
+
+ switch (S->getStmtClass()) {
+ default:
+ continue;
+
+ case Stmt::DefaultStmtClass: {
+
+ os << "Control jumps to the 'default' case at line "
+ << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
+
+ break;
+ }
+
+ case Stmt::CaseStmtClass: {
+
+ os << "Control jumps to 'case ";
+
+ Expr* CondE = cast<SwitchStmt>(T)->getCond();
+ unsigned bits = Ctx.getTypeSize(CondE->getType());
+
+ llvm::APSInt V1(bits, false);
+
+ CaseStmt* Case = cast<CaseStmt>(S);
+
+ if (!Case->getLHS()->isIntegerConstantExpr(V1, Ctx, 0, true)) {
+ assert (false &&
+ "Case condition must evaluate to an integer constant.");
+ continue;
+ }
+
+ os << V1.toString();
+
+ // Get the RHS of the case, if it exists.
+
+ if (Expr* E = Case->getRHS()) {
+
+ llvm::APSInt V2(bits, false);
+
+ if (!E->isIntegerConstantExpr(V2, Ctx, 0, true)) {
+ assert (false &&
+ "Case condition (RHS) must evaluate to an integer constant.");
+ continue;
+ }
+
+ os << " .. " << V2.toString();
+ }
+
+ os << ":' at line "
+ << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
+
+ break;
+
+ }
+ }
+
+ PD.push_front(new PathDiagnosticPiece(L, os.str()));
+ break;
+ }
+
+
+ case Stmt::DoStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::IfStmtClass: {
+
+ if (*(Src->succ_begin()+1) == Dst)
+ PD.push_front(new PathDiagnosticPiece(L, "Taking false branch."));
+ else
+ PD.push_front(new PathDiagnosticPiece(L, "Taking true branch."));
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool BugReporter::IsCached(ExplodedNode<ValueState>* N) {
+
+ // HACK: Cache the location of the error. Don't emit the same
+ // warning for the same error type that occurs at the same program
+ // location but along a different path.
+
+ void* p = N->getLocation().getRawData();
+
+ if (CachedErrors.count(p))
+ return true;
+
+ CachedErrors.insert(p);
+
+ return false;
+}
+
+void BugReporter::EmitPathWarning(Diagnostic& Diag,
+ PathDiagnosticClient* PDC,
+ ASTContext& Ctx,
+ const BugDescription& B,
+ ExplodedGraph<GRExprEngine>& G,
+ ExplodedNode<ValueState>* N) {
+
+ if (!PDC) {
+ EmitWarning(Diag, Ctx, B, N);
+ return;
+ }
+
+ if (IsCached(N))
+ return;
+
+ PathDiagnostic D;
+ GeneratePathDiagnostic(D, Ctx, B, G, N);
+ PDC->HandlePathDiagnostic(D);
+}
+
+
+void BugReporter::EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
+ const BugDescription& B,
+ ExplodedNode<ValueState>* N) {
+ if (IsCached(N))
+ return;
+
+ std::ostringstream os;
+ os << "[CHECKER] " << B.getName();
+
+ unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
+ os.str().c_str());
+
+ // FIXME: Add support for multiple ranges.
+
+ Stmt* S = GetStmt(N->getLocation());
+
+ if (!S)
+ return;
+
+ SourceRange R = S->getSourceRange();
+
+ Diag.Report(FullSourceLoc(S->getLocStart(), Ctx.getSourceManager()),
+ ErrorDiag, NULL, 0, &R, 1);
+}