Skip to content

[analyzer] Introduce the check::BlockEntrance checker callback #140924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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
15 changes: 14 additions & 1 deletion 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 Down Expand Up @@ -46,6 +45,7 @@ class CheckerDocumentation
check::EndAnalysis,
check::EndFunction,
check::EndOfTranslationUnit,
check::BlockEntrance,
check::Event<ImplicitNullDerefEvent>,
check::LiveSymbols,
check::Location,
Expand Down Expand Up @@ -166,6 +166,19 @@ 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.
///
/// \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