[analyzer] Introduce the check::BlockEntrance checker callback by balazs-benics-sonarsource · Pull Request #140924 · llvm/llvm-project (original) (raw)

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balázs Benics (balazs-benics-sonarsource)

Changes

Tranersing the CFG blocks of a function is a fundamental operation. Many C++ constructs can create splits in the control-flow, such as if, for, and similar control structures or ternary expressions, gnu conditionals, gotos, switches and possibly more.

Checkers should be able to get notifications about entering or leaving a CFG block of interest.

Note that in the ExplodedGraph there is always a BlockEntrance ProgramPoint right after the BlockEdge ProgramPoint. I considered naming this callback check::BlockEdge, but then that may leave the observer of the graph puzzled to see BlockEdge points followed more BlockEdge nodes describing the same CFG transition. This confusion could also apply to Bug Report Visitors too.

Because of this, I decided to hook BlockEntrance ProgramPoints instead. The same confusion applies here, but I find this still a better place TBH. There would only appear only one BlockEntrance ProgramPoint in the graph if no checkers modify the state or emit a bug report. Otherwise they modify some GDM (aka. State) thus create a new ExplodedNode with the same BlockEntrance ProgramPoint in the graph.

CPP-6484


Patch is 23.05 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140924.diff

10 Files Affected:

diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index a54c5bee612f6..1b348dcce5ea7 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -221,6 +221,22 @@ class Bind { } };

+class BlockEntrance {

@@ -558,6 +576,8 @@ class Checker : public CHECK1, public CHECKs..., public CheckerBase { template class Checker : public CHECK1, public CheckerBase { public:

diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 03ffadd346d0b..b5fefdb75401d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -376,6 +376,12 @@ class CheckerManager { const Stmt *S, ExprEngine &Eng, const ProgramPoint &PP);

@@ -528,6 +534,9 @@ class CheckerManager { using CheckBindFunc = CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>;

@@ -589,6 +598,8 @@ class CheckerManager {

void _registerForBind(CheckBindFunc checkfn);

@@ -695,6 +706,8 @@ class CheckerManager {

std::vector BindCheckers;

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index b8a4dcbc727a6..6370586e218ef 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -321,6 +321,10 @@ class ExprEngine { NodeBuilderWithSinks &nodeBuilder, ExplodedNode *Pred);

-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"

using namespace clang; using namespace ento; @@ -46,6 +45,7 @@ class CheckerDocumentation check::EndAnalysis, check::EndFunction, check::EndOfTranslationUnit,

@@ -166,6 +166,19 @@ class CheckerDocumentation /// check::Bind void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &) const {}

}

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

+namespace { +struct CheckBlockEntranceContext {

@@ -877,6 +913,10 @@ void CheckerManager::_registerForBind(CheckBindFunc checkfn) { BindCheckers.push_back(checkfn); }

+void CheckerManager::_registerForBlockEntrance(CheckBlockEntranceFunc checkfn) {

}

// Call into the ExprEngine to process entering the CFGBlock.

}

// Enqueue nodes onto the worklist.

void CoreEngine::HandleBlockEntrance(const BlockEntrance &L, diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 1afd4b52eb354..992e451d33081 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2619,6 +2619,19 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, } }

+void ExprEngine::runCheckersForBlockEntrance(const NodeBuilderContext &BldCtx,

@@ -729,7 +730,6 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, return; }

diff --git a/clang/unittests/StaticAnalyzer/BlockEntranceCallbackTest.cpp b/clang/unittests/StaticAnalyzer/BlockEntranceCallbackTest.cpp new file mode 100644 index 0000000000000..729c6d6ebf3ba --- /dev/null +++ b/clang/unittests/StaticAnalyzer/BlockEntranceCallbackTest.cpp @@ -0,0 +1,283 @@ +//===- unittests/StaticAnalyzer/BlockEntranceCallbackTest.cpp -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CheckerRegistration.h" +#include "clang/Analysis/AnalysisDeclContext.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +#include + +using namespace clang; +using namespace ento; + +namespace { + +class BlockEntranceCallbackTester : public Checkercheck::BlockEntrance {

... [truncated]