virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
+ void dumpStack(raw_ostream &OS, StringRef Indent = "") const;
LLVM_ATTRIBUTE_USED void dumpStack() const;
public:
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;
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;
}
}
+void LocationContext::dumpStack() const {
+ dumpStack(llvm::errs());
+}
+
//===----------------------------------------------------------------------===//
// Lazily generated map to query the external variables referenced by a Block.
//===----------------------------------------------------------------------===//
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;
.Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
.Case("clang_analyzer_checkInlined",
&ExprInspectionChecker::analyzerCheckInlined)
+ .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
.Default(0);
if (!Handler)
C.emitReport(R);
}
+void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
+ CheckerContext &C) const {
+ LLVM_BUILTIN_TRAP;
+}
+
void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
Mgr.registerChecker<ExprInspectionChecker>();
}
#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"
void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
unsigned StmtIdx, NodeBuilderContext *Ctx) {
+ PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
currStmtIdx = StmtIdx;
currBldrCtx = Ctx;
ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
return;
}
- currBldrCtx = 0;
}
static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
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");
ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
+ PrettyStackTraceLocationContext StackCrashInfo(Pred->getLocationContext());
currBldrCtx = &BldCtx;
// Check for NULL conditions; e.g. "for(;;)"
clang::ento::ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
+ PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
currBldrCtx = &BuilderCtx;
const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
/// 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;
#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"
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());
/// 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();
--- /dev/null
+//==- 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