From e9c57229f9cbcf2231779a72fa8c3614b212cae3 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Fri, 19 Jul 2013 00:59:08 +0000 Subject: [PATCH] [analyzer] Include analysis stack in crash traces. Sample output: 0. Program arguments: ... 1. parser at end of file 2. While analyzing stack: #0 void inlined() #1 void test() 3. crash-trace.c:6:3: Error evaluating statement llvm-svn: 186639 --- .../include/clang/Analysis/AnalysisContext.h | 1 + clang/lib/Analysis/AnalysisDeclContext.cpp | 16 ++++--- .../Checkers/ExprInspectionChecker.cpp | 7 +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 9 +++- .../Core/ExprEngineCallAndReturn.cpp | 5 ++- .../Core/PrettyStackTraceLocationContext.h | 45 +++++++++++++++++++ 6 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h diff --git a/clang/include/clang/Analysis/AnalysisContext.h b/clang/include/clang/Analysis/AnalysisContext.h index 46d7d07e0907..77ee606ba4b2 100644 --- a/clang/include/clang/Analysis/AnalysisContext.h +++ b/clang/include/clang/Analysis/AnalysisContext.h @@ -256,6 +256,7 @@ public: virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; + void dumpStack(raw_ostream &OS, StringRef Indent = "") const; LLVM_ATTRIBUTE_USED void dumpStack() const; public: diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp index 66dbd3e7856d..465f0c383486 100644 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -410,7 +410,7 @@ bool LocationContext::isParentOf(const LocationContext *LC) const { return false; } -void LocationContext::dumpStack() const { +void LocationContext::dumpStack(raw_ostream &OS, StringRef Indent) const { ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); PrintingPolicy PP(Ctx.getLangOpts()); PP.TerseOutput = 1; @@ -419,15 +419,15 @@ void LocationContext::dumpStack() const { for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) { switch (LCtx->getKind()) { case StackFrame: - llvm::errs() << '#' << Frame++ << ' '; - cast(LCtx)->getDecl()->print(llvm::errs(), PP); - llvm::errs() << '\n'; + OS << Indent << '#' << Frame++ << ' '; + cast(LCtx)->getDecl()->print(OS, PP); + OS << '\n'; break; case Scope: - llvm::errs() << " (scope)\n"; + OS << Indent << " (scope)\n"; break; case Block: - llvm::errs() << " (block context: " + OS << Indent << " (block context: " << cast(LCtx)->getContextData() << ")\n"; break; @@ -435,6 +435,10 @@ void LocationContext::dumpStack() const { } } +void LocationContext::dumpStack() const { + dumpStack(llvm::errs()); +} + //===----------------------------------------------------------------------===// // Lazily generated map to query the external variables referenced by a Block. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 810473f1a6e0..9522d1d6387d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -22,6 +22,7 @@ class ExprInspectionChecker : public Checker< eval::Call > { void analyzerEval(const CallExpr *CE, CheckerContext &C) const; void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const; + void analyzerCrash(const CallExpr *CE, CheckerContext &C) const; typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, CheckerContext &C) const; @@ -39,6 +40,7 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE, .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) .Case("clang_analyzer_checkInlined", &ExprInspectionChecker::analyzerCheckInlined) + .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) .Default(0); if (!Handler) @@ -117,6 +119,11 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, C.emitReport(R); } +void ExprInspectionChecker::analyzerCrash(const CallExpr *CE, + CheckerContext &C) const { + LLVM_BUILTIN_TRAP; +} + void ento::registerExprInspectionChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 0b31495c8401..74ffa1c9af76 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -16,6 +16,7 @@ #define DEBUG_TYPE "ExprEngine" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "PrettyStackTraceLocationContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" @@ -263,6 +264,7 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) { void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, unsigned StmtIdx, NodeBuilderContext *Ctx) { + PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); currStmtIdx = StmtIdx; currBldrCtx = Ctx; @@ -280,7 +282,6 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, ProcessImplicitDtor(E.castAs(), Pred); return; } - currBldrCtx = 0; } static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, @@ -1202,7 +1203,8 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N, void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, NodeBuilderWithSinks &nodeBuilder, ExplodedNode *Pred) { - + PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); + // FIXME: Refactor this into a checker. if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) { static SimpleProgramPointTag tag("ExprEngine : Block count exceeded"); @@ -1326,6 +1328,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF) { + PrettyStackTraceLocationContext StackCrashInfo(Pred->getLocationContext()); currBldrCtx = &BldCtx; // Check for NULL conditions; e.g. "for(;;)" @@ -1426,6 +1429,7 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS, clang::ento::ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF) { + PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); currBldrCtx = &BuilderCtx; const VarDecl *VD = cast(DS->getSingleDecl()); @@ -1491,6 +1495,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { /// nodes when the control reaches the end of a function. void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred) { + PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); StateMgr.EndPath(Pred->getState()); ExplodedNodeSet Dst; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index aa7593e72180..caceb6056920 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "ExprEngine" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "PrettyStackTraceLocationContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ParentMap.h" @@ -39,6 +40,8 @@ STATISTIC(NumReachedInlineCountMax, void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { // Get the entry block in the CFG of the callee. const StackFrameContext *calleeCtx = CE.getCalleeContext(); + PrettyStackTraceLocationContext CrashInfo(calleeCtx); + const CFG *CalleeCFG = calleeCtx->getCFG(); const CFGBlock *Entry = &(CalleeCFG->getEntry()); @@ -214,7 +217,7 @@ static bool isTemporaryPRValue(const CXXConstructExpr *E, SVal V) { /// 5. PostStmt void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // Step 1 CEBNode was generated before the call. - + PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext()); const StackFrameContext *calleeCtx = CEBNode->getLocationContext()->getCurrentStackFrame(); diff --git a/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h new file mode 100644 index 000000000000..ed64fcbec761 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h @@ -0,0 +1,45 @@ +//==- PrettyStackTraceLocationContext.h - show analysis backtrace --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_PRETTYSTACKTRACELOCATIONCONTEXT_H +#define LLVM_CLANG_STATICANALYZER_PRETTYSTACKTRACELOCATIONCONTEXT_H + +#include "clang/Analysis/AnalysisContext.h" + +namespace clang { +namespace ento { + +/// While alive, includes the current analysis stack in a crash trace. +/// +/// Example: +/// \code +/// 0. Program arguments: ... +/// 1. parser at end of file +/// 2. While analyzing stack: +/// #0 void inlined() +/// #1 void test() +/// 3. crash-trace.c:6:3: Error evaluating statement +/// \endcode +class PrettyStackTraceLocationContext : public llvm::PrettyStackTraceEntry { + const LocationContext *LCtx; +public: + PrettyStackTraceLocationContext(const LocationContext *LC) : LCtx(LC) { + assert(LCtx); + } + + virtual void print(raw_ostream &OS) const { + OS << "While analyzing stack: \n"; + LCtx->dumpStack(OS, "\t"); + } +}; + +} // end ento namespace +} // end clang namespace + +#endif