Skip to content
20 changes: 20 additions & 0 deletions clang/include/clang/StaticAnalyzer/Core/Checker.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,22 @@ class Bind {
}
};

class BlockEntrance {
template <typename CHECKER>
static void _checkBlockEntrance(void *Checker,
const clang::BlockEntrance &Entrance,
CheckerContext &C) {
((const CHECKER *)Checker)->checkBlockEntrance(Entrance, C);
}

public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
mgr._registerForBlockEntrance(CheckerManager::CheckBlockEntranceFunc(
checker, _checkBlockEntrance<CHECKER>));
}
};

class EndAnalysis {
template <typename CHECKER>
static void _checkEndAnalysis(void *checker, ExplodedGraph &G,
Expand Down Expand Up @@ -548,6 +564,8 @@ class CheckerProgramPointTag : public SimpleProgramPointTag {
template <typename CHECK1, typename... CHECKs>
class Checker : public CHECK1, public CHECKs..., public CheckerBase {
public:
using BlockEntrance = clang::BlockEntrance;

template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
CHECK1::_register(checker, mgr);
Expand All @@ -558,6 +576,8 @@ class Checker : public CHECK1, public CHECKs..., public CheckerBase {
template <typename CHECK1>
class Checker<CHECK1> : public CHECK1, public CheckerBase {
public:
using BlockEntrance = clang::BlockEntrance;

template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
CHECK1::_register(checker, mgr);
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,12 @@ class CheckerManager {
const Stmt *S, ExprEngine &Eng,
const ProgramPoint &PP);

/// Run checkers after taking a control flow edge.
void runCheckersForBlockEntrance(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const BlockEntrance &Entrance,
ExprEngine &Eng) const;

/// Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
Expand Down Expand Up @@ -528,6 +534,9 @@ class CheckerManager {
using CheckBindFunc =
CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>;

using CheckBlockEntranceFunc =
CheckerFn<void(const BlockEntrance &, CheckerContext &)>;

using CheckEndAnalysisFunc =
CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>;

Expand Down Expand Up @@ -589,6 +598,8 @@ class CheckerManager {

void _registerForBind(CheckBindFunc checkfn);

void _registerForBlockEntrance(CheckBlockEntranceFunc checkfn);

void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);

void _registerForBeginFunction(CheckBeginFunctionFunc checkfn);
Expand Down Expand Up @@ -695,6 +706,8 @@ class CheckerManager {

std::vector<CheckBindFunc> BindCheckers;

std::vector<CheckBlockEntranceFunc> BlockEntranceCheckers;

std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;

std::vector<CheckBeginFunctionFunc> BeginFunctionCheckers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@ class ExprEngine {
NodeBuilderWithSinks &nodeBuilder,
ExplodedNode *Pred);

void runCheckersForBlockEntrance(const NodeBuilderContext &BldCtx,
const BlockEntrance &Entrance,
ExplodedNode *Pred, ExplodedNodeSet &Dst);

/// ProcessBranch - Called by CoreEngine. Used to generate successor nodes by
/// processing the 'effects' of a branch condition. If the branch condition
/// is a loop condition, IterationsCompletedInLoop is the number of completed
Expand Down
34 changes: 32 additions & 2 deletions clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"

using namespace clang;
using namespace ento;
Expand All @@ -40,6 +39,7 @@ class CheckerDocumentation
check::ASTDecl<FunctionDecl>,
check::BeginFunction,
check::Bind,
check::BlockEntrance,
check::BranchCondition,
check::ConstPointerEscape,
check::DeadSymbols,
Expand Down Expand Up @@ -129,7 +129,20 @@ class CheckerDocumentation
/// check::PostCall
void checkPostCall(const CallEvent &Call, CheckerContext &C) const {}

/// Pre-visit of the condition statement of a branch (such as IfStmt).
/// Pre-visit of the condition statement of a branch.
/// For example:
/// - logical operators (&&, ||)
/// - if, do, while, for, ranged-for statements
/// - ternary operators (?:), gnu conditionals, gnu choose expressions
/// Interestingly, switch statements don't seem to trigger BranchCondition.
///
/// check::BlockEntrance is a similar callback, which is strictly more
/// generic. Prefer check::BranchCondition to check::BlockEntrance if
/// pre-visiting conditional statements is enough for the checker.
/// Note that check::BlockEntrance is also invoked for leaving basic blocks
/// while entering the next.
///
/// check::BranchCondition
void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const {}

/// Post-visit the C++ operator new's allocation call.
Expand Down Expand Up @@ -166,6 +179,23 @@ class CheckerDocumentation
/// check::Bind
void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &) const {}

/// Called after a CFG edge is taken within a function.
///
/// This callback can be used to obtain information about potential branching
/// points or any other constructs that involve traversing a CFG edge.
/// Note that when inlining a call, there is no CFG edge between the caller
/// and the callee. One will only see the edge between the entry block and
/// the body of the function once inlined.
///
/// check::BranchCondition is a similar callback, which is only invoked for
/// pre-visiting the condition statement of a branch. Prefer that callback if
/// possible.
///
/// \param E The ProgramPoint that describes the transition.
///
/// check::BlockEntrance
void checkBlockEntrance(const BlockEntrance &E, CheckerContext &) const {}

/// Called whenever a symbol becomes dead.
///
/// This callback should be used by the checkers to aggressively clean
Expand Down
50 changes: 45 additions & 5 deletions clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ bool CheckerManager::hasPathSensitiveCheckers() const {
return IfAnyAreNonEmpty(
StmtCheckers, PreObjCMessageCheckers, ObjCMessageNilCheckers,
PostObjCMessageCheckers, PreCallCheckers, PostCallCheckers,
LocationCheckers, BindCheckers, EndAnalysisCheckers,
BeginFunctionCheckers, EndFunctionCheckers, BranchConditionCheckers,
NewAllocatorCheckers, LiveSymbolsCheckers, DeadSymbolsCheckers,
RegionChangesCheckers, PointerEscapeCheckers, EvalAssumeCheckers,
EvalCallCheckers, EndOfTranslationUnitCheckers);
LocationCheckers, BindCheckers, BlockEntranceCheckers,
EndAnalysisCheckers, BeginFunctionCheckers, EndFunctionCheckers,
BranchConditionCheckers, NewAllocatorCheckers, LiveSymbolsCheckers,
DeadSymbolsCheckers, RegionChangesCheckers, PointerEscapeCheckers,
EvalAssumeCheckers, EvalCallCheckers, EndOfTranslationUnitCheckers);
}

void CheckerManager::reportInvalidCheckerOptionValue(
Expand Down Expand Up @@ -420,6 +420,42 @@ void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
expandGraphWithCheckers(C, Dst, Src);
}

namespace {
struct CheckBlockEntranceContext {
using CheckBlockEntranceFunc = CheckerManager::CheckBlockEntranceFunc;
using CheckersTy = std::vector<CheckBlockEntranceFunc>;

const CheckersTy &Checkers;
const BlockEntrance &Entrance;
ExprEngine &Eng;

CheckBlockEntranceContext(const CheckersTy &Checkers,
const BlockEntrance &Entrance, ExprEngine &Eng)
: Checkers(Checkers), Entrance(Entrance), Eng(Eng) {}

auto checkers_begin() const { return Checkers.begin(); }
auto checkers_end() const { return Checkers.end(); }

void runChecker(CheckBlockEntranceFunc CheckFn, NodeBuilder &Bldr,
ExplodedNode *Pred) {
llvm::TimeTraceScope TimeScope(
checkerScopeName("BlockEntrance", CheckFn.Checker));
CheckerContext C(Bldr, Eng, Pred, Entrance.withTag(CheckFn.Checker));
CheckFn(Entrance, C);
}
};

} // namespace

void CheckerManager::runCheckersForBlockEntrance(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const BlockEntrance &Entrance,
ExprEngine &Eng) const {
CheckBlockEntranceContext C(BlockEntranceCheckers, Entrance, Eng);
llvm::TimeTraceScope TimeScope{"CheckerManager::runCheckersForBlockEntrance"};
expandGraphWithCheckers(C, Dst, Src);
}

void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
BugReporter &BR,
ExprEngine &Eng) {
Expand Down Expand Up @@ -877,6 +913,10 @@ void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
BindCheckers.push_back(checkfn);
}

void CheckerManager::_registerForBlockEntrance(CheckBlockEntranceFunc checkfn) {
BlockEntranceCheckers.push_back(checkfn);
}

void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
EndAnalysisCheckers.push_back(checkfn);
}
Expand Down
25 changes: 18 additions & 7 deletions clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,26 +306,37 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
}
}

ExplodedNodeSet CheckerNodes;
BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, Pred, CheckerNodes);

// Process the final state transition.
ExprEng.processEndOfFunction(BuilderCtx, Pred, RS);
for (ExplodedNode *P : CheckerNodes) {
ExprEng.processEndOfFunction(BuilderCtx, P, RS);
}

// This path is done. Don't enqueue any more nodes.
return;
}

// Call into the ExprEngine to process entering the CFGBlock.
ExplodedNodeSet dstNodes;
BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
ExprEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
ExplodedNodeSet DstNodes;
NodeBuilderWithSinks NodeBuilder(Pred, DstNodes, BuilderCtx, BE);
ExprEng.processCFGBlockEntrance(L, NodeBuilder, Pred);

// Auto-generate a node.
if (!nodeBuilder.hasGeneratedNodes()) {
nodeBuilder.generateNode(Pred->State, Pred);
if (!NodeBuilder.hasGeneratedNodes()) {
NodeBuilder.generateNode(Pred->State, Pred);
}

ExplodedNodeSet CheckerNodes;
for (auto *N : DstNodes) {
ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, N, CheckerNodes);
}

// Enqueue nodes onto the worklist.
enqueue(dstNodes);
enqueue(CheckerNodes);
}

void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2619,6 +2619,19 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
}
}

void ExprEngine::runCheckersForBlockEntrance(const NodeBuilderContext &BldCtx,
const BlockEntrance &Entrance,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
llvm::PrettyStackTraceFormat CrashInfo(
"Processing block entrance B%d -> B%d",
Entrance.getPreviousBlock()->getBlockID(),
Entrance.getBlock()->getBlockID());
currBldrCtx = &BldCtx;
getCheckerManager().runCheckersForBlockEntrance(Dst, Pred, Entrance, *this);
currBldrCtx = nullptr;
}

//===----------------------------------------------------------------------===//
// Branch processing.
//===----------------------------------------------------------------------===//
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,9 +711,10 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
}

ExplodedNode *N = Pred;
while (!N->getLocation().getAs<BlockEntrance>()) {
while (!N->getLocation().getAs<BlockEdge>()) {
ProgramPoint P = N->getLocation();
assert(P.getAs<PreStmt>()|| P.getAs<PreStmtPurgeDeadSymbols>());
assert(P.getAs<PreStmt>() || P.getAs<PreStmtPurgeDeadSymbols>() ||
P.getAs<BlockEntrance>());
(void) P;
if (N->pred_size() != 1) {
// We failed to track back where we came from.
Expand All @@ -729,7 +730,6 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
return;
}

N = *N->pred_begin();
BlockEdge BE = N->getLocation().castAs<BlockEdge>();
SVal X;

Expand Down
Loading