[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

llvm-svn: 186639
This commit is contained in:
Jordan Rose 2013-07-19 00:59:08 +00:00
parent 978c839315
commit e9c57229f9
6 changed files with 74 additions and 9 deletions

View File

@ -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:

View File

@ -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<StackFrameContext>(LCtx)->getDecl()->print(llvm::errs(), PP);
llvm::errs() << '\n';
OS << Indent << '#' << Frame++ << ' ';
cast<StackFrameContext>(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<BlockInvocationContext>(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.
//===----------------------------------------------------------------------===//

View File

@ -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<ExprInspectionChecker>();
}

View File

@ -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<CFGImplicitDtor>(), 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<VarDecl>(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;

View File

@ -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<CallExpr>
void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// Step 1 CEBNode was generated before the call.
PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext());
const StackFrameContext *calleeCtx =
CEBNode->getLocationContext()->getCurrentStackFrame();

View File

@ -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