blob: 5e1460c5fb64dbdeea5f36eaef9645aa5b0634a1 [file] [log] [blame]
Wei Yi Tee543af742022-06-01 06:52:24 -07001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#include "nullability_verification/pointer_nullability_analysis.h"
6
Wei Yi Tee543af742022-06-01 06:52:24 -07007#include <string>
8
9#include "common/check.h"
10#include "nullability_verification/pointer_nullability_lattice.h"
11#include "nullability_verification/pointer_nullability_matchers.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/AST/Expr.h"
Wei Yi Tee1cd62af2022-06-09 00:56:46 -070014#include "clang/AST/OperationKinds.h"
15#include "clang/AST/Stmt.h"
16#include "clang/AST/Type.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070017#include "clang/ASTMatchers/ASTMatchFinder.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070018#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
19#include "clang/Analysis/FlowSensitive/MatchSwitch.h"
20#include "clang/Analysis/FlowSensitive/Value.h"
21#include "clang/Basic/LLVM.h"
22
23namespace clang {
24namespace tidy {
25namespace nullability {
26
27using ast_matchers::MatchFinder;
28using dataflow::BoolValue;
29using dataflow::Environment;
30using dataflow::MatchSwitchBuilder;
31using dataflow::PointerValue;
32using dataflow::SkipPast;
33using dataflow::TransferState;
34using dataflow::Value;
35
36namespace {
37
Wei Yi Teec46666a2022-08-02 09:38:40 -070038constexpr llvm::StringLiteral kNotNull = "is_notnull";
39
Wei Yi Tee85d87372022-06-09 01:01:35 -070040BoolValue& getPointerNotNullProperty(
Wei Yi Tee1cd62af2022-06-09 00:56:46 -070041 const Expr* PointerExpr, TransferState<PointerNullabilityLattice>& State) {
42 auto* PointerVal =
43 cast<PointerValue>(State.Env.getValue(*PointerExpr, SkipPast::Reference));
Wei Yi Teec46666a2022-08-02 09:38:40 -070044 return *cast<BoolValue>(PointerVal->getProperty(kNotNull));
Wei Yi Tee1cd62af2022-06-09 00:56:46 -070045}
46
Wei Yi Teec46666a2022-08-02 09:38:40 -070047void initPointerNotNullProperty(const Expr* PointerExpr,
48 TransferState<PointerNullabilityLattice>& State,
49 BoolValue* NotNull = nullptr) {
Wei Yi Tee543af742022-06-01 06:52:24 -070050 if (auto* PointerVal = cast_or_null<PointerValue>(
Wei Yi Teef02698e2022-06-10 04:25:48 -070051 State.Env.getValue(*PointerExpr, SkipPast::Reference))) {
Wei Yi Teec46666a2022-08-02 09:38:40 -070052 if (PointerVal->getProperty(kNotNull) == nullptr) {
53 NotNull = NotNull ? NotNull : &State.Env.makeAtomicBoolValue();
54 PointerVal->setProperty(kNotNull, *NotNull);
Wei Yi Tee543af742022-06-01 06:52:24 -070055 }
56 }
57}
58
Wei Yi Teec46666a2022-08-02 09:38:40 -070059void transferInitNotNullPointer(
60 const Expr* NotNullPointer, const MatchFinder::MatchResult&,
61 TransferState<PointerNullabilityLattice>& State) {
62 initPointerNotNullProperty(NotNullPointer, State,
63 &State.Env.getBoolLiteralValue(true));
64}
65
66void transferInitNullPointer(const Expr* NullPointer,
67 const MatchFinder::MatchResult& Result,
68 TransferState<PointerNullabilityLattice>& State) {
69 initPointerNotNullProperty(NullPointer, State,
70 &State.Env.getBoolLiteralValue(false));
71}
72
Wei Yi Teef02698e2022-06-10 04:25:48 -070073void transferInitPointerVariableReference(
Wei Yi Teecebc2262022-06-10 04:27:57 -070074 const Expr* PointerExpr, const MatchFinder::MatchResult&,
Wei Yi Teef02698e2022-06-10 04:25:48 -070075 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Teec46666a2022-08-02 09:38:40 -070076 initPointerNotNullProperty(PointerExpr, State);
Wei Yi Tee1cd62af2022-06-09 00:56:46 -070077}
78
Wei Yi Teef02698e2022-06-10 04:25:48 -070079void transferPointerAccess(const Expr* PointerExpr,
80 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Tee85d87372022-06-09 01:01:35 -070081 auto& PointerNotNull = getPointerNotNullProperty(PointerExpr, State);
82 if (!State.Env.flowConditionImplies(PointerNotNull)) {
Wei Yi Tee1cd62af2022-06-09 00:56:46 -070083 State.Lattice.addViolation(PointerExpr);
Wei Yi Tee543af742022-06-01 06:52:24 -070084 }
Wei Yi Tee543af742022-06-01 06:52:24 -070085}
86
Wei Yi Teef02698e2022-06-10 04:25:48 -070087void transferDereference(const UnaryOperator* UnaryOp,
88 const MatchFinder::MatchResult&,
89 TransferState<PointerNullabilityLattice>& State) {
90 transferPointerAccess(UnaryOp->getSubExpr(), State);
91}
92
93void transferMemberExprInvolvingPointers(
94 const MemberExpr* MemberExpr, const MatchFinder::MatchResult&,
95 TransferState<PointerNullabilityLattice>& State) {
96 if (MemberExpr->isArrow()) {
97 // Base expr is a pointer, check that (->) access is safe
98 transferPointerAccess(MemberExpr->getBase(), State);
99 }
100 if (MemberExpr->getType()->isAnyPointerType()) {
101 // Accessed member is a pointer, initialise its nullability
Wei Yi Teec46666a2022-08-02 09:38:40 -0700102 initPointerNotNullProperty(MemberExpr, State);
Wei Yi Teef02698e2022-06-10 04:25:48 -0700103 }
104}
105
Wei Yi Tee543af742022-06-01 06:52:24 -0700106void transferNullCheckComparison(
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700107 const BinaryOperator* BinaryOp, const MatchFinder::MatchResult& result,
Wei Yi Tee543af742022-06-01 06:52:24 -0700108 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700109 // Boolean representing the comparison between the two pointer values,
110 // automatically created by the dataflow framework
111 auto& PointerComparison =
112 *cast<BoolValue>(State.Env.getValue(*BinaryOp, SkipPast::None));
Wei Yi Tee543af742022-06-01 06:52:24 -0700113
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700114 CHECK(BinaryOp->getOpcode() == BO_EQ || BinaryOp->getOpcode() == BO_NE);
115 auto& PointerEQ = BinaryOp->getOpcode() == BO_EQ
116 ? PointerComparison
117 : State.Env.makeNot(PointerComparison);
118 auto& PointerNE = BinaryOp->getOpcode() == BO_EQ
119 ? State.Env.makeNot(PointerComparison)
120 : PointerComparison;
121
Wei Yi Tee85d87372022-06-09 01:01:35 -0700122 auto& LHSNotNull = getPointerNotNullProperty(BinaryOp->getLHS(), State);
123 auto& RHSNotNull = getPointerNotNullProperty(BinaryOp->getRHS(), State);
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700124
125 // !LHS && !RHS => LHS == RHS
126 State.Env.addToFlowCondition(State.Env.makeImplication(
Wei Yi Tee85d87372022-06-09 01:01:35 -0700127 State.Env.makeAnd(State.Env.makeNot(LHSNotNull),
128 State.Env.makeNot(RHSNotNull)),
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700129 PointerEQ));
130 // !LHS && RHS => LHS != RHS
131 State.Env.addToFlowCondition(State.Env.makeImplication(
Wei Yi Tee85d87372022-06-09 01:01:35 -0700132 State.Env.makeAnd(State.Env.makeNot(LHSNotNull), RHSNotNull), PointerNE));
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700133 // LHS && !RHS => LHS != RHS
134 State.Env.addToFlowCondition(State.Env.makeImplication(
Wei Yi Tee85d87372022-06-09 01:01:35 -0700135 State.Env.makeAnd(LHSNotNull, State.Env.makeNot(RHSNotNull)), PointerNE));
Wei Yi Tee543af742022-06-01 06:52:24 -0700136}
137
138void transferNullCheckImplicitCastPtrToBool(
139 const Expr* CastExpr, const MatchFinder::MatchResult&,
140 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Teec46666a2022-08-02 09:38:40 -0700141 auto& PointerNotNull =
142 getPointerNotNullProperty(CastExpr->IgnoreImplicit(), State);
143 auto& CastExprLoc = State.Env.createStorageLocation(*CastExpr);
144 State.Env.setValue(CastExprLoc, PointerNotNull);
145 State.Env.setStorageLocation(*CastExpr, CastExprLoc);
Wei Yi Tee543af742022-06-01 06:52:24 -0700146}
147
148auto buildTransferer() {
149 return MatchSwitchBuilder<TransferState<PointerNullabilityLattice>>()
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700150 // Handles initialization of the null states of pointers
Wei Yi Tee85d87372022-06-09 01:01:35 -0700151 .CaseOf<Expr>(isPointerVariableReference(),
Wei Yi Teef02698e2022-06-10 04:25:48 -0700152 transferInitPointerVariableReference)
Wei Yi Teec46666a2022-08-02 09:38:40 -0700153 .CaseOf<Expr>(isCXXThisExpr(), transferInitNotNullPointer)
154 .CaseOf<Expr>(isAddrOf(), transferInitNotNullPointer)
155 .CaseOf<Expr>(isNullPointerLiteral(), transferInitNullPointer)
Wei Yi Teef02698e2022-06-10 04:25:48 -0700156 // Handles initialization of null states of member pointers and safety of
157 // member access (->) on pointers
158 .CaseOf<MemberExpr>(isMemberExprInvolvingPointers(),
159 transferMemberExprInvolvingPointers)
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700160 // Handles pointer dereferencing (*ptr)
Wei Yi Tee543af742022-06-01 06:52:24 -0700161 .CaseOf<UnaryOperator>(isPointerDereference(), transferDereference)
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700162 // Handles comparison between 2 pointers
163 .CaseOf<BinaryOperator>(isPointerCheckBinOp(),
164 transferNullCheckComparison)
165 // Handles checking of pointer as boolean
166 .CaseOf<Expr>(isImplicitCastPointerToBool(),
Wei Yi Tee543af742022-06-01 06:52:24 -0700167 transferNullCheckImplicitCastPtrToBool)
168 .Build();
169}
170} // namespace
171
172PointerNullabilityAnalysis::PointerNullabilityAnalysis(ASTContext& Context)
173 : DataflowAnalysis<PointerNullabilityAnalysis, PointerNullabilityLattice>(
174 Context),
175 Transferer(buildTransferer()) {}
176
177void PointerNullabilityAnalysis::transfer(const Stmt* Stmt,
178 PointerNullabilityLattice& Lattice,
179 Environment& Env) {
180 TransferState<PointerNullabilityLattice> State(Lattice, Env);
181 Transferer(*Stmt, getASTContext(), State);
182}
183
184bool PointerNullabilityAnalysis::merge(QualType Type, const Value& Val1,
185 const Environment& Env1,
186 const Value& Val2,
187 const Environment& Env2,
188 Value& MergedVal,
189 Environment& MergedEnv) {
190 return false;
191}
192} // namespace nullability
193} // namespace tidy
194} // namespace clang