#include #include #include #include #include #include #include #include #include #include ">

clang: lib/StaticAnalyzer/Core/BugReporter.cpp File Reference (original) (raw)

#include "[clang/StaticAnalyzer/Core/BugReporter/BugReporter.h](BugReporter%5F8h%5Fsource.html)"
#include "[clang/AST/ASTTypeTraits.h](ASTTypeTraits%5F8h%5Fsource.html)"
#include "[clang/AST/Attr.h](AST%5F2Attr%5F8h%5Fsource.html)"
#include "[clang/AST/Decl.h](Decl%5F8h%5Fsource.html)"
#include "[clang/AST/DeclBase.h](DeclBase%5F8h%5Fsource.html)"
#include "[clang/AST/DeclObjC.h](DeclObjC%5F8h%5Fsource.html)"
#include "[clang/AST/Expr.h](Expr%5F8h%5Fsource.html)"
#include "[clang/AST/ExprCXX.h](ExprCXX%5F8h%5Fsource.html)"
#include "[clang/AST/ParentMap.h](ParentMap%5F8h%5Fsource.html)"
#include "[clang/AST/ParentMapContext.h](ParentMapContext%5F8h%5Fsource.html)"
#include "[clang/AST/Stmt.h](Stmt%5F8h%5Fsource.html)"
#include "[clang/AST/StmtCXX.h](StmtCXX%5F8h%5Fsource.html)"
#include "[clang/AST/StmtObjC.h](StmtObjC%5F8h%5Fsource.html)"
#include "[clang/Analysis/AnalysisDeclContext.h](AnalysisDeclContext%5F8h%5Fsource.html)"
#include "[clang/Analysis/CFG.h](CFG%5F8h%5Fsource.html)"
#include "[clang/Analysis/CFGStmtMap.h](CFGStmtMap%5F8h%5Fsource.html)"
#include "[clang/Analysis/PathDiagnostic.h](PathDiagnostic%5F8h%5Fsource.html)"
#include "[clang/Analysis/ProgramPoint.h](ProgramPoint%5F8h%5Fsource.html)"
#include "[clang/Basic/LLVM.h](LLVM%5F8h%5Fsource.html)"
#include "[clang/Basic/SourceLocation.h](SourceLocation%5F8h%5Fsource.html)"
#include "[clang/Basic/SourceManager.h](SourceManager%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/AnalyzerOptions.h](AnalyzerOptions%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h](BugReporterVisitors%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/BugReporter/BugType.h](BugType%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/BugReporter/Z3CrosscheckVisitor.h](Z3CrosscheckVisitor%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/Checker.h](Checker%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/CheckerManager.h](CheckerManager%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/CheckerRegistryData.h](CheckerRegistryData%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h](ExplodedGraph%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h](ExprEngine%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h](MemRegion%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h](ProgramState%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h](SMTConv%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/PathSensitive/SVals.h](SVals%5F8h%5Fsource.html)"
#include "[clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h](SymbolManager%5F8h%5Fsource.html)"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <memory>
#include <optional>
#include <queue>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

Go to the source code of this file.

Functions
STATISTIC (MaxBugClassSize, "The maximum number of bug reports in the same equivalence class")
STATISTIC (MaxValidBugClassSize, "The maximum number of bug reports in the same equivalence class " "where at least one report is valid (not suppressed)")
STATISTIC (NumTimesReportPassesZ3, "Number of reports passed Z3")
STATISTIC (NumTimesReportRefuted, "Number of reports refuted by Z3")
STATISTIC (NumTimesReportEQClassAborted, "Number of times a report equivalence class was aborted by the Z3 " "oracle heuristic")
STATISTIC (NumTimesReportEQClassWasExhausted, "Number of times all reports of an equivalence class was refuted")
static PathDiagnosticEventPiece * eventsDescribeSameCondition (PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
static void removeRedundantMsgs (PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBRVisitor and TrackConstraintBRVisitor.
static bool removeUnneededCalls (const PathDiagnosticConstruct &C, PathPieces &pieces, const PathSensitiveBugReport *R, bool IsInteresting=false)
Recursively scan through a path and prune out calls and macros pieces that aren't needed.
static void removePopUpNotes (PathPieces &Path)
Same logic as above to remove extra pieces.
static bool hasImplicitBody (const Decl *D)
Returns true if the given decl has been implicitly given a body, either by the analyzer or by the compiler proper.
static void adjustCallLocations (PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
static void removeEdgesToDefaultInitializers (PathPieces &Pieces)
Remove edges in and out of C++ default initializer expressions.
static void removePiecesWithInvalidLocations (PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
static const Stmt * getEnclosingParent (const Stmt *S, const ParentMap &PM)
static PathDiagnosticLocation getEnclosingStmtLocation (const Stmt *S, const LocationContext *LC, bool allowNestedContexts=false)
static void CompactMacroExpandedPieces (PathPieces &path, const SourceManager &SM)
CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDiagosticPieces that are expanded by macros.
static bool isLoop (const Stmt *Term)
static bool isJumpToFalseBranch (const BlockEdge *BE)
static bool isContainedByStmt (const ParentMap &PM, const Stmt *S, const Stmt *SubS)
static const Stmt * getStmtBeforeCond (const ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
static bool isInLoopBody (const ParentMap &PM, const Stmt *S, const Stmt *Term)
static void addEdgeToPath (PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
static const Stmt * getTerminatorCondition (const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForCollectionStmts.
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines (const SourceManager &SM, const ExplodedNode *N)
static std::unique_ptr< PathDiagnostic > generateDiagnosticForBasicReport (const BasicBugReport *R, const Decl *AnalysisEntryPoint)
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport (const PathSensitiveBugReport *R, const SourceManager &SM, const Decl *AnalysisEntryPoint)
static const Stmt * getStmtParent (const Stmt *S, const ParentMap &PM)
static bool isConditionForTerminator (const Stmt *S, const Stmt *Cond)
static bool isIncrementOrInitInForLoop (const Stmt *S, const Stmt *FL)
static void addContextEdges (PathPieces &pieces, const LocationContext *LC)
Adds synthetic edges from top-level statements to their subexpressions.
static void simplifySimpleBranches (PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
static std::optional< size_t > getLengthOnSingleLine (const SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
static std::optional< size_t > getLengthOnSingleLine (const SourceManager &SM, const Stmt *S)
static void removeContextCycles (PathPieces &Path, const SourceManager &SM)
Eliminate two-edge cycles created by addContextEdges().
static bool lexicalContains (const ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
static void removePunyEdges (PathPieces &path, const SourceManager &SM, const ParentMap &PM)
static void removeIdenticalEvents (PathPieces &path)
static bool optimizeEdges (const PathDiagnosticConstruct &C, PathPieces &path, OptimizedCallsSet &OCS)
static void dropFunctionEntryEdge (const PathDiagnosticConstruct &C, PathPieces &Path)
Drop the very first edge in a path, which should be a function entry edge.
static void updateExecutedLinesWithDiagnosticPieces (PathDiagnostic &PD)
Populate executes lines with lines containing at least one diagnostics.
static LLVM_ATTRIBUTE_USED bool isDependency (const CheckerRegistryData &Registry, StringRef CheckerName)
static LLVM_ATTRIBUTE_USED bool isHidden (const CheckerRegistryData &Registry, StringRef CheckerName)
template
static void insertToInterestingnessMap (llvm::DenseMap< T, bugreporter::TrackingKind > &InterestingnessMap, T Val, bugreporter::TrackingKind TKind)
static bool exitingDestructor (const ExplodedNode *N)
static const Stmt * findReasonableStmtCloseToFunctionExit (const ExplodedNode *N)
static std::unique_ptr< VisitorsDiagnosticsTy > generateVisitorsDiagnostics (PathSensitiveBugReport *R, const ExplodedNode *ErrorNode, BugReporterContext &BRC)
Generate notes from all visitors.
static void populateExecutedLinesWithFunctionSignature (const Decl *Signature, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
Insert all lines participating in the function signature Signature into ExecutedLines.
static void populateExecutedLinesWithStmt (const Stmt *S, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile (PathDiagnosticCallPiece *CP, const SourceManager &SMgr)
static void resetDiagnosticLocationToMainFile (PathDiagnostic &PD)
Variables
constexpr llvm::StringLiteral StrEnteringLoop = "Entering loop body"
constexpr llvm::StringLiteral StrLoopBodyZero = "Loop body executed 0 times"
constexpr llvm::StringLiteral StrLoopRangeEmpty
constexpr llvm::StringLiteral StrLoopCollectionEmpty

DEBUG_TYPE

#define DEBUG_TYPE "BugReporter"

OptimizedCallsSet

addContextEdges()

Adds synthetic edges from top-level statements to their subexpressions.

This avoids a "swoosh" effect, where an edge from a top-level statement A points to a sub-expression B.1 that's not at the start of B. In these cases, we'd like to see an edge from A to B, then another one from B to B.1.

Definition at line 1430 of file BugReporter.cpp.

References clang::ento::PathDiagnosticLocation::asStmt(), E, getEnclosingStmtLocation(), clang::LocationContext::getParentMap(), clang::ento::PathDiagnosticLocation::getStmtOrNull(), getStmtParent(), clang::ento::PathDiagnosticLocation::isValid(), and P.

Referenced by optimizeEdges().

addEdgeToPath()

adjustCallLocations()

CompactMacroExpandedPieces()

dropFunctionEntryEdge()

static void dropFunctionEntryEdge ( const PathDiagnosticConstruct & C, PathPieces & Path ) static

eventsDescribeSameCondition()

exitingDestructor()

findExecutedLines()

Returns

all executed lines including function signatures on the path starting from N.

Definition at line 3232 of file BugReporter.cpp.

References D, clang::LocationContext::getDecl(), clang::ento::ExplodedNode::getFirstPred(), clang::ento::ExplodedNode::getLocationAs(), clang::ento::ExplodedNode::getLocationContext(), clang::ParentMap::getParent(), clang::ento::ExplodedNode::getParentMap(), clang::ento::ExplodedNode::getStmtForDiagnostics(), P, populateExecutedLinesWithFunctionSignature(), populateExecutedLinesWithStmt(), and SM.

Referenced by generateEmptyDiagnosticForReport().

findReasonableStmtCloseToFunctionExit()

static const Stmt * findReasonableStmtCloseToFunctionExit ( const ExplodedNode * N) static

generateDiagnosticForBasicReport()

generateEmptyDiagnosticForReport()

Definition at line 1343 of file BugReporter.cpp.

References findExecutedLines(), clang::ento::BugReport::getBugType(), clang::ento::BugType::getCategory(), clang::ento::BugType::getCheckerName(), clang::ento::PathSensitiveBugReport::getDeclWithIssue(), clang::ento::BugReport::getDescription(), clang::ento::BugType::getDescription(), clang::ento::PathSensitiveBugReport::getErrorNode(), clang::ento::BugReport::getShortDescription(), clang::ento::PathSensitiveBugReport::getUniqueingDecl(), clang::ento::PathSensitiveBugReport::getUniqueingLocation(), and SM.

generateVisitorsDiagnostics()

getEnclosingParent()

static const Stmt * getEnclosingParent ( const Stmt * S, const ParentMap & PM ) static

getEnclosingStmtLocation()

getFirstStackedCallToHeaderFile()

getLengthOnSingleLine() [1/2]

getLengthOnSingleLine() [2/2]

getStmtBeforeCond()

getStmtParent()

getTerminatorCondition()

static const Stmt * getTerminatorCondition ( const CFGBlock * B) static

hasImplicitBody()

static bool hasImplicitBody ( const Decl * D) static

insertToInterestingnessMap()

isConditionForTerminator()

static bool isConditionForTerminator ( const Stmt * S, const Stmt * Cond ) static

isContainedByStmt()

isDependency()

static LLVM_ATTRIBUTE_USED bool isDependency ( const CheckerRegistryData & Registry, StringRef CheckerName ) static

isHidden()

isIncrementOrInitInForLoop()

static bool isIncrementOrInitInForLoop ( const Stmt * S, const Stmt * FL ) static

isInLoopBody()

isJumpToFalseBranch()

isLoop()

static bool isLoop ( const Stmt * Term) static

lexicalContains()

optimizeEdges()

Definition at line 1772 of file BugReporter.cpp.

References addContextEdges(), clang::C, E, getLengthOnSingleLine(), clang::LocationContext::getParentMap(), getStmtParent(), isConditionForTerminator(), clang::ParentMap::isConsumedExpr(), isIncrementOrInitInForLoop(), lexicalContains(), optimizeEdges(), removeContextCycles(), removeIdenticalEvents(), removePunyEdges(), simplifySimpleBranches(), and SM.

Referenced by optimizeEdges().

populateExecutedLinesWithFunctionSignature()

populateExecutedLinesWithStmt()

removeContextCycles()

Eliminate two-edge cycles created by addContextEdges().

Once all the context edges are in place, there are plenty of cases where there's a single edge from a top-level statement to a subexpression, followed by a single path note, and then a reverse edge to get back out to the top level. If the statement is simple enough, the subexpression edges just add noise and make it harder to understand what's going on.

This function only removes edges in pairs, because removing only one edge might leave other edges dangling.

This will not remove edges in more complicated situations:

  • if there is more than one "hop" leading to or from a subexpression.
  • if there is an inlined call between the edges instead of a single event.
  • if the whole statement is large enough that having subexpression arrows might be helpful.

Definition at line 1631 of file BugReporter.cpp.

References E, getLengthOnSingleLine(), Path, and SM.

Referenced by optimizeEdges().

removeEdgesToDefaultInitializers()

static void removeEdgesToDefaultInitializers ( PathPieces & Pieces) static

removeIdenticalEvents()

static void removeIdenticalEvents ( PathPieces & path) static

removePiecesWithInvalidLocations()

static void removePiecesWithInvalidLocations ( PathPieces & Pieces) static

removePopUpNotes()

static void removePopUpNotes ( PathPieces & Path) static

removePunyEdges()

removeRedundantMsgs()

static void removeRedundantMsgs ( PathPieces & path) static

removeUnneededCalls()

resetDiagnosticLocationToMainFile()

static void resetDiagnosticLocationToMainFile ( PathDiagnostic & PD) static

Definition at line 3308 of file BugReporter.cpp.

References clang::ento::PathDiagnostic::appendToDesc(), clang::ento::PathDiagnosticCallPiece::getCallee(), clang::ento::PathDiagnosticCallPiece::getCaller(), getFirstStackedCallToHeaderFile(), clang::ento::PathDiagnosticPiece::getLocation(), clang::ento::PathDiagnosticCallPiece::getLocation(), clang::ento::PathDiagnosticLocation::getManager(), clang::ento::PathDiagnostic::path, clang::ento::PathDiagnosticPiece::setAsLastInMainSourceFile(), clang::ento::PathDiagnostic::setDeclWithIssue(), and clang::ento::PathDiagnostic::setLocation().

simplifySimpleBranches()

static void simplifySimpleBranches ( PathPieces & pieces) static

Move edges from a branch condition to a branch target when the condition is simple.

This restructures some of the work of addContextEdges. That function creates edges this may destroy, but they work together to create a more aesthetically set of edges around branches. After the call to addContextEdges, we may have (1) an edge to the branch, (2) an edge from the branch to the branch condition, and (3) an edge from the branch condition to the branch target. We keep (1), but may wish to remove (2) and move the source of (3) to the branch if the branch condition is simple.

Definition at line 1511 of file BugReporter.cpp.

References E, clang::ento::PathDiagnosticControlFlowPiece::getEndLocation(), clang::ento::PathDiagnosticControlFlowPiece::getStartLocation(), clang::ento::PathDiagnosticLocation::getStmtOrNull(), clang::isa(), isConditionForTerminator(), clang::ento::PathDiagnosticControlFlowPiece::setStartLocation(), StrEnteringLoop, StrLoopBodyZero, StrLoopCollectionEmpty, and StrLoopRangeEmpty.

Referenced by optimizeEdges().

STATISTIC() [1/6]

STATISTIC ( MaxBugClassSize ,
"The maximum number of bug reports in the same equivalence class"
)

STATISTIC() [2/6]

STATISTIC ( MaxValidBugClassSize ,
"The maximum number of bug reports in the same equivalence class " "where at least one report is valid (not suppressed)"
)

STATISTIC() [3/6]

STATISTIC ( NumTimesReportEQClassAborted ,
"Number of times a report equivalence class was aborted by the Z3 " "oracle heuristic"
)

STATISTIC() [4/6]

STATISTIC ( NumTimesReportEQClassWasExhausted ,
"Number of times all reports of an equivalence class was refuted"
)

STATISTIC() [5/6]

STATISTIC ( NumTimesReportPassesZ3 ,
"Number of reports passed Z3"
)

STATISTIC() [6/6]

STATISTIC ( NumTimesReportRefuted ,
"Number of reports refuted by Z3"
)

updateExecutedLinesWithDiagnosticPieces()

static void updateExecutedLinesWithDiagnosticPieces ( PathDiagnostic & PD) static

StrEnteringLoop

constexpr llvm::StringLiteral StrEnteringLoop = "Entering loop body" constexpr

StrLoopBodyZero

constexpr llvm::StringLiteral StrLoopBodyZero = "Loop body executed 0 times" constexpr

StrLoopCollectionEmpty

constexpr llvm::StringLiteral StrLoopCollectionEmpty constexpr

StrLoopRangeEmpty

constexpr llvm::StringLiteral StrLoopRangeEmpty constexpr