diff options
author | Ted Kremenek <kremenek@apple.com> | 2013-05-03 18:25:33 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2013-05-03 18:25:33 +0000 |
commit | af2836593979d4973bec5bd21f10eb6cc0d0f3e3 (patch) | |
tree | 493023a496502598e1e68cec2646b3692b66ac83 | |
parent | 634c5634817b9ad384a706fe87ab302985566bba (diff) |
[analyzer] Start hacking up alternate control-flow edge generation. WIP. Not guaranteed to do anything useful yet.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181040 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h | 2 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporter.cpp | 216 |
2 files changed, 217 insertions, 1 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 9de0a5fba3..c7c02461be 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -94,7 +94,7 @@ public: void HandlePathDiagnostic(PathDiagnostic *D); - enum PathGenerationScheme { None, Minimal, Extensive }; + enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } virtual bool supportsAllBlockEdges() const { return false; } diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index b1c3a13db7..4606b2151d 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1530,6 +1530,212 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, return PDB.getBugReport()->isValid(); } +/// \brief Adds a sanitized control-flow diagnostic edge to a path. +static void addEdgeToPath(PathPieces &path, + PathDiagnosticLocation &PrevLoc, + PathDiagnosticLocation NewLoc, + const LocationContext *LC) { + if (NewLoc.asLocation().isMacroID()) + return; + + if (!PrevLoc.isValid()) { + PrevLoc = NewLoc; + return; + } + + const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc, LC); + if (PrevLocClean.asLocation().isInvalid()) { + PrevLoc = NewLoc; + return; + } + + const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc, LC); + if (NewLocClean.asLocation() == PrevLocClean.asLocation()) + return; + + // FIXME: ignore intra-macro edges for now. + if (NewLocClean.asLocation().getExpansionLoc() == + PrevLocClean.asLocation().getExpansionLoc()) + return; + + path.push_front(new PathDiagnosticControlFlowPiece(NewLocClean, + PrevLocClean)); + PrevLoc = NewLoc; +} + +static bool +GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, + PathDiagnosticBuilder &PDB, + const ExplodedNode *N, + LocationContextMap &LCM, + ArrayRef<BugReporterVisitor *> visitors) { + + BugReport *report = PDB.getBugReport(); + const SourceManager& SM = PDB.getSourceManager(); + StackDiagVector CallStack; + InterestingExprs IE; + + // Record the last location for a given visited stack frame. + llvm::DenseMap<const StackFrameContext *, PathDiagnosticLocation> + PrevLocMap; + + const ExplodedNode *NextNode = N->getFirstPred(); + while (NextNode) { + N = NextNode; + NextNode = N->getFirstPred(); + ProgramPoint P = N->getLocation(); + const LocationContext *LC = N->getLocationContext(); + PathDiagnosticLocation &PrevLoc = PrevLocMap[LC->getCurrentStackFrame()]; + + do { + if (Optional<PostStmt> PS = P.getAs<PostStmt>()) { + // For expressions, make sure we propagate the + // interesting symbols correctly. + if (const Expr *Ex = PS->getStmtAs<Expr>()) + reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), Ex, + N->getLocationContext()); + break; + } + + // Have we encountered an exit from a function call? + if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) { + const Stmt *S = CE->getCalleeContext()->getCallSite(); + // Propagate the interesting symbols accordingly. + if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { + reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), Ex, + N->getLocationContext()); + } + + // We are descending into a call (backwards). Construct + // a new call piece to contain the path pieces for that call. + PathDiagnosticCallPiece *C = + PathDiagnosticCallPiece::construct(N, *CE, SM); + + // Record the location context for this call piece. + LCM[C] = CE->getCalleeContext(); + + // Add the edge to the return site. + addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, LC); + + // Make the contents of the call the active path for now. + PD.pushActivePath(&C->path); + CallStack.push_back(StackDiagPair(C, N)); + break; + } + + // Have we encountered an entrance to a call? It may be + // the case that we have not encountered a matching + // call exit before this point. This means that the path + // terminated within the call itself. + if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { + // Add an edge to the start of the function. + const Decl *D = CE->getCalleeContext()->getDecl(); + addEdgeToPath(PD.getActivePath(), PrevLoc, + PathDiagnosticLocation::createBegin(D, SM), LC); + + // Did we visit an entire call? + bool VisitedEntireCall = PD.isWithinCall(); + PD.popActivePath(); + + PathDiagnosticCallPiece *C; + if (VisitedEntireCall) { + C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front()); + } else { + const Decl *Caller = CE->getLocationContext()->getDecl(); + C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); + LCM[C] = CE->getCalleeContext(); + } + C->setCallee(*CE, SM); + + if (!CallStack.empty()) { + assert(CallStack.back().first == C); + CallStack.pop_back(); + } + break; + } + + // Block edges. + if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { + // Does this represent entering a call? If so, look at propagating + // interesting symbols across call boundaries. + if (NextNode) { + const LocationContext *CallerCtx = NextNode->getLocationContext(); + const LocationContext *CalleeCtx = PDB.LC; + if (CallerCtx != CalleeCtx) { + reversePropagateInterestingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), + CalleeCtx, CallerCtx); + } + } + + // Are we jumping to the head of a loop? Add a special diagnostic. + if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { + PathDiagnosticLocation L(Loop, SM, PDB.LC); + const CompoundStmt *CS = NULL; + + if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(FS->getBody()); + else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(WS->getBody()); + + PathDiagnosticEventPiece *p = + new PathDiagnosticEventPiece(L, "Looping back to the head " + "of the loop"); + p->setPrunable(true); + + addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC); + + if (CS) { + addEdgeToPath(PD.getActivePath(), PrevLoc, + PathDiagnosticLocation::createEndBrace(CS, SM), LC); + } + } + + const CFGBlock *BSrc = BE->getSrc(); + ParentMap &PM = PDB.getParentMap(); + + if (const Stmt *Term = BSrc->getTerminator()) { + // Are we jumping past the loop body without ever executing the + // loop (because the condition was false)? + if (isLoopJumpPastBody(Term, &*BE) && + !isInLoopBody(PM, + getStmtBeforeCond(PM, + BSrc->getTerminatorCondition(), + N), + Term)) + { + PathDiagnosticLocation L(Term, SM, PDB.LC); + PathDiagnosticEventPiece *PE = + new PathDiagnosticEventPiece(L, "Loop body executed 0 times"); + PE->setPrunable(true); + addEdgeToPath(PD.getActivePath(), PrevLoc, + PE->getLocation(), LC); + } + } + break; + } + } while (0); + + if (!NextNode) + continue; + + // Add pieces from custom visitors. + BugReport *R = PDB.getBugReport(); + for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(), + E = visitors.end(); + I != E; ++I) { + if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) { + addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC); + updateStackPiecesWithMessage(p, CallStack); + } + } + } + + return report->isValid(); +} + //===----------------------------------------------------------------------===// // Methods for BugType and subclasses. //===----------------------------------------------------------------------===// @@ -2108,6 +2314,13 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, typedef PathDiagnosticConsumer::PathGenerationScheme PathGenerationScheme; PathGenerationScheme ActiveScheme = PC.getGenerationScheme(); + if (ActiveScheme == PathDiagnosticConsumer::Extensive) { + AnalyzerOptions &options = getEngine().getAnalysisManager().options; + if (options.getBooleanOption("path-diagnostics-alternate", false)) { + ActiveScheme = PathDiagnosticConsumer::AlternateExtensive; + } + } + TrimmedGraph TrimG(&getGraph(), errorNodes); ReportGraph ErrorGraph; @@ -2169,6 +2382,9 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, LCM.clear(); switch (ActiveScheme) { + case PathDiagnosticConsumer::AlternateExtensive: + GenerateAlternateExtensivePathDiagnostic(PD, PDB, N, LCM, visitors); + break; case PathDiagnosticConsumer::Extensive: GenerateExtensivePathDiagnostic(PD, PDB, N, LCM, visitors); break; |