Browse Source

[analyzer] Include analysis stack in crash traces.

Sample output:

0.     Program arguments: ...
1.     <eof> parser at end of file
2.     While analyzing stack:
       #0 void inlined()
       #1 void test()
3.     crash-trace.c:6:3: Error evaluating statement

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186639 91177308-0d34-0410-b5e6-96231b3b80d8
Jordan Rose 12 years ago
parent
commit
ac7cc2d37e

+ 1 - 0
include/clang/Analysis/AnalysisContext.h

@@ -256,6 +256,7 @@ public:
 
 
   virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
   virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
 
 
+  void dumpStack(raw_ostream &OS, StringRef Indent = "") const;
   LLVM_ATTRIBUTE_USED void dumpStack() const;
   LLVM_ATTRIBUTE_USED void dumpStack() const;
 
 
 public:
 public:

+ 10 - 6
lib/Analysis/AnalysisDeclContext.cpp

@@ -410,7 +410,7 @@ bool LocationContext::isParentOf(const LocationContext *LC) const {
   return false;
   return false;
 }
 }
 
 
-void LocationContext::dumpStack() const {
+void LocationContext::dumpStack(raw_ostream &OS, StringRef Indent) const {
   ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
   ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
   PrintingPolicy PP(Ctx.getLangOpts());
   PrintingPolicy PP(Ctx.getLangOpts());
   PP.TerseOutput = 1;
   PP.TerseOutput = 1;
@@ -419,15 +419,15 @@ void LocationContext::dumpStack() const {
   for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
   for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
     switch (LCtx->getKind()) {
     switch (LCtx->getKind()) {
     case StackFrame:
     case StackFrame:
-      llvm::errs() << '#' << Frame++ << ' ';
-      cast<StackFrameContext>(LCtx)->getDecl()->print(llvm::errs(), PP);
-      llvm::errs() << '\n';
+      OS << Indent << '#' << Frame++ << ' ';
+      cast<StackFrameContext>(LCtx)->getDecl()->print(OS, PP);
+      OS << '\n';
       break;
       break;
     case Scope:
     case Scope:
-      llvm::errs() << "    (scope)\n";
+      OS << Indent << "    (scope)\n";
       break;
       break;
     case Block:
     case Block:
-      llvm::errs() << "    (block context: "
+      OS << Indent << "    (block context: "
                    << cast<BlockInvocationContext>(LCtx)->getContextData()
                    << cast<BlockInvocationContext>(LCtx)->getContextData()
                    << ")\n";
                    << ")\n";
       break;
       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.
 // Lazily generated map to query the external variables referenced by a Block.
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//

+ 7 - 0
lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp

@@ -22,6 +22,7 @@ class ExprInspectionChecker : public Checker< eval::Call > {
 
 
   void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
   void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
   void analyzerCheckInlined(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 *,
   typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
                                                  CheckerContext &C) const;
                                                  CheckerContext &C) const;
@@ -39,6 +40,7 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE,
     .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
     .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
     .Case("clang_analyzer_checkInlined",
     .Case("clang_analyzer_checkInlined",
           &ExprInspectionChecker::analyzerCheckInlined)
           &ExprInspectionChecker::analyzerCheckInlined)
+    .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
     .Default(0);
     .Default(0);
 
 
   if (!Handler)
   if (!Handler)
@@ -117,6 +119,11 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
   C.emitReport(R);
   C.emitReport(R);
 }
 }
 
 
+void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
+                                          CheckerContext &C) const {
+  LLVM_BUILTIN_TRAP;
+}
+
 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
   Mgr.registerChecker<ExprInspectionChecker>();
   Mgr.registerChecker<ExprInspectionChecker>();
 }
 }

+ 7 - 2
lib/StaticAnalyzer/Core/ExprEngine.cpp

@@ -16,6 +16,7 @@
 #define DEBUG_TYPE "ExprEngine"
 #define DEBUG_TYPE "ExprEngine"
 
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "PrettyStackTraceLocationContext.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/ParentMap.h"
 #include "clang/AST/ParentMap.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtCXX.h"
@@ -263,6 +264,7 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
 
 
 void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
 void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
                                    unsigned StmtIdx, NodeBuilderContext *Ctx) {
                                    unsigned StmtIdx, NodeBuilderContext *Ctx) {
+  PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
   currStmtIdx = StmtIdx;
   currStmtIdx = StmtIdx;
   currBldrCtx = Ctx;
   currBldrCtx = Ctx;
 
 
@@ -280,7 +282,6 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
       ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
       ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
       return;
       return;
   }
   }
-  currBldrCtx = 0;
 }
 }
 
 
 static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
 static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
@@ -1202,7 +1203,8 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
 void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
 void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
                                          NodeBuilderWithSinks &nodeBuilder, 
                                          NodeBuilderWithSinks &nodeBuilder, 
                                          ExplodedNode *Pred) {
                                          ExplodedNode *Pred) {
-  
+  PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+
   // FIXME: Refactor this into a checker.
   // FIXME: Refactor this into a checker.
   if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) {
   if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) {
     static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
     static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
@@ -1326,6 +1328,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
                                ExplodedNodeSet &Dst,
                                ExplodedNodeSet &Dst,
                                const CFGBlock *DstT,
                                const CFGBlock *DstT,
                                const CFGBlock *DstF) {
                                const CFGBlock *DstF) {
+  PrettyStackTraceLocationContext StackCrashInfo(Pred->getLocationContext());
   currBldrCtx = &BldCtx;
   currBldrCtx = &BldCtx;
 
 
   // Check for NULL conditions; e.g. "for(;;)"
   // Check for NULL conditions; e.g. "for(;;)"
@@ -1426,6 +1429,7 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS,
                                           clang::ento::ExplodedNodeSet &Dst,
                                           clang::ento::ExplodedNodeSet &Dst,
                                           const CFGBlock *DstT,
                                           const CFGBlock *DstT,
                                           const CFGBlock *DstF) {
                                           const CFGBlock *DstF) {
+  PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
   currBldrCtx = &BuilderCtx;
   currBldrCtx = &BuilderCtx;
 
 
   const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
   const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
@@ -1491,6 +1495,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
 ///  nodes when the control reaches the end of a function.
 ///  nodes when the control reaches the end of a function.
 void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
 void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
                                       ExplodedNode *Pred) {
                                       ExplodedNode *Pred) {
+  PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
   StateMgr.EndPath(Pred->getState());
   StateMgr.EndPath(Pred->getState());
 
 
   ExplodedNodeSet Dst;
   ExplodedNodeSet Dst;

+ 4 - 1
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

@@ -14,6 +14,7 @@
 #define DEBUG_TYPE "ExprEngine"
 #define DEBUG_TYPE "ExprEngine"
 
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "PrettyStackTraceLocationContext.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/ParentMap.h"
 #include "clang/AST/ParentMap.h"
@@ -39,6 +40,8 @@ STATISTIC(NumReachedInlineCountMax,
 void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
 void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
   // Get the entry block in the CFG of the callee.
   // Get the entry block in the CFG of the callee.
   const StackFrameContext *calleeCtx = CE.getCalleeContext();
   const StackFrameContext *calleeCtx = CE.getCalleeContext();
+  PrettyStackTraceLocationContext CrashInfo(calleeCtx);
+
   const CFG *CalleeCFG = calleeCtx->getCFG();
   const CFG *CalleeCFG = calleeCtx->getCFG();
   const CFGBlock *Entry = &(CalleeCFG->getEntry());
   const CFGBlock *Entry = &(CalleeCFG->getEntry());
   
   
@@ -214,7 +217,7 @@ static bool isTemporaryPRValue(const CXXConstructExpr *E, SVal V) {
 /// 5. PostStmt<CallExpr>
 /// 5. PostStmt<CallExpr>
 void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
 void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
   // Step 1 CEBNode was generated before the call.
   // Step 1 CEBNode was generated before the call.
-
+  PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext());
   const StackFrameContext *calleeCtx =
   const StackFrameContext *calleeCtx =
       CEBNode->getLocationContext()->getCurrentStackFrame();
       CEBNode->getLocationContext()->getCurrentStackFrame();
   
   

+ 45 - 0
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.     <eof> 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