1 //=== UndefBranchChecker.cpp -----------------------------------*- C++ -*--===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines UndefBranchChecker, which checks for undefined branch
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"
24 using namespace clang
;
29 class UndefBranchChecker
: public Checker
<check::BranchCondition
> {
30 mutable std::unique_ptr
<BugType
> BT
;
32 struct FindUndefExpr
{
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
))
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
))
51 bool MatchesCriteria(const Expr
*Ex
) {
52 return St
->getSVal(Ex
, LCtx
).isUndef();
57 void checkBranchCondition(const Stmt
*Condition
, CheckerContext
&Ctx
) const;
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
))
67 SVal X
= Ctx
.getSVal(Condition
);
69 // Generate a sink node, which implicitly marks both outgoing branches as
71 ExplodedNode
*N
= Ctx
.generateErrorNode();
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
) {