[DFAJumpThreading] Remove incoming StartBlock from all phis when unfolding select...
[llvm-project.git] / clang / lib / StaticAnalyzer / Checkers / UndefBranchChecker.cpp
blobdb886501a162d0dfe3d9241eaab248645149749d
1 //=== UndefBranchChecker.cpp -----------------------------------*- C++ -*--===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines UndefBranchChecker, which checks for undefined branch
10 // condition.
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/StmtObjC.h"
15 #include "clang/AST/Type.h"
16 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
17 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18 #include "clang/StaticAnalyzer/Core/Checker.h"
19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 #include <optional>
22 #include <utility>
24 using namespace clang;
25 using namespace ento;
27 namespace {
29 class UndefBranchChecker : public Checker<check::BranchCondition> {
30 mutable std::unique_ptr<BugType> BT;
32 struct FindUndefExpr {
33 ProgramStateRef St;
34 const LocationContext *LCtx;
36 FindUndefExpr(ProgramStateRef S, const LocationContext *L)
37 : St(std::move(S)), LCtx(L) {}
39 const Expr *FindExpr(const Expr *Ex) {
40 if (!MatchesCriteria(Ex))
41 return nullptr;
43 for (const Stmt *SubStmt : Ex->children())
44 if (const Expr *ExI = dyn_cast_or_null<Expr>(SubStmt))
45 if (const Expr *E2 = FindExpr(ExI))
46 return E2;
48 return Ex;
51 bool MatchesCriteria(const Expr *Ex) {
52 return St->getSVal(Ex, LCtx).isUndef();
56 public:
57 void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const;
60 } // namespace
62 void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
63 CheckerContext &Ctx) const {
64 // ObjCForCollection is a loop, but has no actual condition.
65 if (isa<ObjCForCollectionStmt>(Condition))
66 return;
67 SVal X = Ctx.getSVal(Condition);
68 if (X.isUndef()) {
69 // Generate a sink node, which implicitly marks both outgoing branches as
70 // infeasible.
71 ExplodedNode *N = Ctx.generateErrorNode();
72 if (N) {
73 if (!BT)
74 BT.reset(
75 new BugType(this, "Branch condition evaluates to a garbage value"));
77 // What's going on here: we want to highlight the subexpression of the
78 // condition that is the most likely source of the "uninitialized
79 // branch condition." We do a recursive walk of the condition's
80 // subexpressions and roughly look for the most nested subexpression
81 // that binds to Undefined. We then highlight that expression's range.
83 // Get the predecessor node and check if is a PostStmt with the Stmt
84 // being the terminator condition. We want to inspect the state
85 // of that node instead because it will contain main information about
86 // the subexpressions.
88 // Note: any predecessor will do. They should have identical state,
89 // since all the BlockEdge did was act as an error sink since the value
90 // had to already be undefined.
91 assert (!N->pred_empty());
92 const Expr *Ex = cast<Expr>(Condition);
93 ExplodedNode *PrevN = *N->pred_begin();
94 ProgramPoint P = PrevN->getLocation();
95 ProgramStateRef St = N->getState();
97 if (std::optional<PostStmt> PS = P.getAs<PostStmt>())
98 if (PS->getStmt() == Ex)
99 St = PrevN->getState();
101 FindUndefExpr FindIt(St, Ctx.getLocationContext());
102 Ex = FindIt.FindExpr(Ex);
104 // Emit the bug report.
105 auto R = std::make_unique<PathSensitiveBugReport>(
106 *BT, BT->getDescription(), N);
107 bugreporter::trackExpressionValue(N, Ex, *R);
108 R->addRange(Ex->getSourceRange());
110 Ctx.emitReport(std::move(R));
115 void ento::registerUndefBranchChecker(CheckerManager &mgr) {
116 mgr.registerChecker<UndefBranchChecker>();
119 bool ento::shouldRegisterUndefBranchChecker(const CheckerManager &mgr) {
120 return true;