clang 23.0.0git
UndefBranchChecker.cpp
Go to the documentation of this file.
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.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/StmtObjC.h"
15#include "clang/AST/Type.h"
21#include <optional>
22#include <utility>
23
24using namespace clang;
25using namespace ento;
26
27namespace {
28
29class UndefBranchChecker : public Checker<check::BranchCondition> {
30 const BugType BT{this, "Branch condition evaluates to a garbage value"};
31
32 struct FindUndefExpr {
34 const LocationContext *LCtx;
35
36 FindUndefExpr(ProgramStateRef S, const LocationContext *L)
37 : St(std::move(S)), LCtx(L) {}
38
39 const Expr *FindExpr(const Expr *Ex) {
40 if (!MatchesCriteria(Ex))
41 return nullptr;
42
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;
47
48 return Ex;
49 }
50
51 bool MatchesCriteria(const Expr *Ex) {
52 return St->getSVal(Ex, LCtx).isUndef();
53 }
54 };
55
56public:
57 void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const;
58};
59
60} // namespace
61
62void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
63 CheckerContext &Ctx) const {
64 // ObjCForCollection is a loop, but has no actual condition.
66 return;
67
68 const auto *Ex = cast<Expr>(Condition);
69 if (!Ctx.getSVal(Ex).isUndef())
70 return;
71
72 // Generate a sink node, which implicitly marks both outgoing branches as
73 // infeasible.
74 ExplodedNode *N = Ctx.generateErrorNode();
75 if (!N)
76 return;
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.
82
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.
87
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 ExplodedNode *PrevN = *N->pred_begin();
93 ProgramPoint P = PrevN->getLocation();
94 ProgramStateRef St = N->getState();
95
96 if (std::optional<PostStmt> PS = P.getAs<PostStmt>())
97 if (PS->getStmt() == Ex)
98 St = PrevN->getState();
99
100 FindUndefExpr FindIt(St, Ctx.getLocationContext());
101 Ex = FindIt.FindExpr(Ex);
102
103 // Emit the bug report.
104 auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
106 R->addRange(Ex->getSourceRange());
107
108 Ctx.emitReport(std::move(R));
109}
110
111void ento::registerUndefBranchChecker(CheckerManager &mgr) {
112 mgr.registerChecker<UndefBranchChecker>();
113}
114
115bool ento::shouldRegisterUndefBranchChecker(const CheckerManager &mgr) {
116 return true;
117}
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
Stmt - This represents one statement.
Definition Stmt.h:86
child_range children()
Definition Stmt.cpp:304
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
StringRef getDescription() const
Definition BugType.h:58
SVal getSVal(const Expr *E) const
Get the value of arbitrary expressions at this point in the path.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
const LocationContext * getLocationContext() const
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:553
const ProgramStateRef & getState() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
bool isUndef() const
Definition SVals.h:107
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
Definition Facts.h:91
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327