clang 10.0.0git

TrustNonnullChecker.cpp
Go to the documentation of this file.
1 //== TrustNonnullChecker.cpp --------- API nullability modeling -*- 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 checker adds nullability-related assumptions:
10 //
11 // 1. Methods annotated with _Nonnull
12 // which come from system headers actually return a non-null pointer.
13 //
14 // 2. NSDictionary key is non-null after the keyword subscript operation
15 // on read if and only if the resulting expression is non-null.
16 //
17 // 3. NSMutableDictionary index is non-null after a write operation.
18 //
19 //===----------------------------------------------------------------------===//
20
21 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
22 #include "clang/Analysis/SelectorExtras.h"
23 #include "clang/StaticAnalyzer/Core/Checker.h"
24 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
25 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
27 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
28
29 using namespace clang;
30 using namespace ento;
31
32 /// Records implications between symbols.
33 /// The semantics is:
34 /// (antecedent != 0) => (consequent != 0)
35 /// These implications are then read during the evaluation of the assumption,
36 /// and the appropriate antecedents are applied.
37 REGISTER_MAP_WITH_PROGRAMSTATE(NonNullImplicationMap, SymbolRef, SymbolRef)
38
39 /// The semantics is:
40 /// (antecedent == 0) => (consequent == 0)
41 REGISTER_MAP_WITH_PROGRAMSTATE(NullImplicationMap, SymbolRef, SymbolRef)
42
43 namespace {
44
45 class TrustNonnullChecker : public Checker<check::PostCall,
46 check::PostObjCMessage,
47 check::DeadSymbols,
48 eval::Assume> {
49 // Do not try to iterate over symbols with higher complexity.
50 static unsigned constexpr ComplexityThreshold = 10;
51 Selector ObjectForKeyedSubscriptSel;
52 Selector ObjectForKeySel;
53 Selector SetObjectForKeyedSubscriptSel;
54 Selector SetObjectForKeySel;
55
56 public:
57 TrustNonnullChecker(ASTContext &Ctx)
58 : ObjectForKeyedSubscriptSel(
59 getKeywordSelector(Ctx, "objectForKeyedSubscript")),
60 ObjectForKeySel(getKeywordSelector(Ctx, "objectForKey")),
61 SetObjectForKeyedSubscriptSel(
62 getKeywordSelector(Ctx, "setObject", "forKeyedSubscript")),
63 SetObjectForKeySel(getKeywordSelector(Ctx, "setObject", "forKey")) {}
64
65 ProgramStateRef evalAssume(ProgramStateRef State,
66 SVal Cond,
67 bool Assumption) const {
68 const SymbolRef CondS = Cond.getAsSymbol();
69 if (!CondS || CondS->computeComplexity() > ComplexityThreshold)
70 return State;
71
72 for (auto B=CondS->symbol_begin(), E=CondS->symbol_end(); B != E; ++B) {
73 const SymbolRef Antecedent = *B;
74 State = addImplication(Antecedent, State, true);
75 State = addImplication(Antecedent, State, false);
76 }
77
78 return State;
79 }
80
81 void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
82 // Only trust annotations for system headers for non-protocols.
83 if (!Call.isInSystemHeader())
84 return;
85
86 ProgramStateRef State = C.getState();
87
88 if (isNonNullPtr(Call, C))
89 if (auto L = Call.getReturnValue().getAs<Loc>())
90 State = State->assume(*L, /*assumption=*/true);
91
92 C.addTransition(State);
93 }
94
95 void checkPostObjCMessage(const ObjCMethodCall &Msg,
96 CheckerContext &C) const {
97 const ObjCInterfaceDecl *ID = Msg.getReceiverInterface();
98 if (!ID)
99 return;
100
101 ProgramStateRef State = C.getState();
102
103 // Index to setter for NSMutableDictionary is assumed to be non-null,
104 // as an exception is thrown otherwise.
105 if (interfaceHasSuperclass(ID, "NSMutableDictionary") &&
106 (Msg.getSelector() == SetObjectForKeyedSubscriptSel ||
107 Msg.getSelector() == SetObjectForKeySel)) {
108 if (auto L = Msg.getArgSVal(1).getAs<Loc>())
109 State = State->assume(*L, /*assumption=*/true);
110 }
111
112 // Record an implication: index is non-null if the output is non-null.
113 if (interfaceHasSuperclass(ID, "NSDictionary") &&
114 (Msg.getSelector() == ObjectForKeyedSubscriptSel ||
115 Msg.getSelector() == ObjectForKeySel)) {
116 SymbolRef ArgS = Msg.getArgSVal(0).getAsSymbol();
117 SymbolRef RetS = Msg.getReturnValue().getAsSymbol();
118
119 if (ArgS && RetS) {
120 // Emulate an implication: the argument is non-null if
121 // the return value is non-null.
122 State = State->set<NonNullImplicationMap>(RetS, ArgS);
123
124 // Conversely, when the argument is null, the return value
125 // is definitely null.
126 State = State->set<NullImplicationMap>(ArgS, RetS);
127 }
128 }
129
130 C.addTransition(State);
131 }
132
133 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const {
134 ProgramStateRef State = C.getState();
135
136 State = dropDeadFromGDM<NullImplicationMap>(SymReaper, State);
137 State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper, State);
138
139 C.addTransition(State);
140 }
141
142 private:
143
144 /// \returns State with GDM \p MapName where all dead symbols were
145 // removed.
146 template <typename MapName>
147 ProgramStateRef dropDeadFromGDM(SymbolReaper &SymReaper,
148 ProgramStateRef State) const {
149 for (const std::pair<SymbolRef, SymbolRef> &P : State->get<MapName>())
150 if (!SymReaper.isLive(P.first) || !SymReaper.isLive(P.second))
151 State = State->remove<MapName>(P.first);
152 return State;
153 }
154
155 /// \returns Whether we trust the result of the method call to be
156 /// a non-null pointer.
157 bool isNonNullPtr(const CallEvent &Call, CheckerContext &C) const {
158 QualType ExprRetType = Call.getResultType();
159 if (!ExprRetType->isAnyPointerType())
160 return false;
161
162 if (getNullabilityAnnotation(ExprRetType) == Nullability::Nonnull)
163 return true;
164
165 // The logic for ObjC instance method calls is more complicated,
166 // as the return value is nil when the receiver is nil.
167 if (!isa<ObjCMethodCall>(&Call))
168 return false;
169
170 const auto *MCall = cast<ObjCMethodCall>(&Call);
171 const ObjCMethodDecl *MD = MCall->getDecl();
172
173 // Distrust protocols.
174 if (isa<ObjCProtocolDecl>(MD->getDeclContext()))
175 return false;
176
177 QualType DeclRetType = MD->getReturnType();
178 if (getNullabilityAnnotation(DeclRetType) != Nullability::Nonnull)
179 return false;
180
181 // For class messages it is sufficient for the declaration to be
182 // annotated _Nonnull.
183 if (!MCall->isInstanceMessage())
184 return true;
185
186 // Alternatively, the analyzer could know that the receiver is not null.
187 SVal Receiver = MCall->getReceiverSVal();
188 ConditionTruthVal TV = C.getState()->isNonNull(Receiver);
189 if (TV.isConstrainedTrue())
190 return true;
191
192 return false;
193 }
194
195 /// \return Whether \p ID has a superclass by the name \p ClassName.
196 bool interfaceHasSuperclass(const ObjCInterfaceDecl *ID,
197 StringRef ClassName) const {
198 if (ID->getIdentifier()->getName() == ClassName)
199 return true;
200
201 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
202 return interfaceHasSuperclass(Super, ClassName);
203
204 return false;
205 }
206
207
208 /// \return a state with an optional implication added (if exists)
209 /// from a map of recorded implications.
210 /// If \p Negated is true, checks NullImplicationMap, and assumes
211 /// the negation of \p Antecedent.
212 /// Checks NonNullImplicationMap and assumes \p Antecedent otherwise.
213 ProgramStateRef addImplication(SymbolRef Antecedent,
214 ProgramStateRef InputState,
215 bool Negated) const {
216 if (!InputState)
217 return nullptr;
218 SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
219 const SymbolRef *Consequent =
220 Negated ? InputState->get<NonNullImplicationMap>(Antecedent)
221 : InputState->get<NullImplicationMap>(Antecedent);
222 if (!Consequent)
223 return InputState;
224
225 SVal AntecedentV = SVB.makeSymbolVal(Antecedent);
226 ProgramStateRef State = InputState;
227
228 if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
229 || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
230 SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
231 State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
232 if (!State)
233 return nullptr;
234
235 // Drop implications from the map.
236 if (Negated) {
237 State = State->remove<NonNullImplicationMap>(Antecedent);
238 State = State->remove<NullImplicationMap>(*Consequent);
239 } else {
240 State = State->remove<NullImplicationMap>(Antecedent);
241 State = State->remove<NonNullImplicationMap>(*Consequent);
242 }
243 }
244
245 return State;
246 }
247 };
248
249 } // end empty namespace
250
251 void ento::registerTrustNonnullChecker(CheckerManager &Mgr) {
252 Mgr.registerChecker<TrustNonnullChecker>(Mgr.getASTContext());
253 }
254
255 bool ento::shouldRegisterTrustNonnullChecker(const LangOptions &LO) {
256 return true;
257 }
clang::Builtin::ID
ID
Definition: Builtins.h:46
ento
clang::Selector
Smart pointer class that efficiently represents Objective-C method names.
Definition: IdentifierTable.h:685
clang::ento::Nullability::Nonnull
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:654
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
P
StringRef P
Definition: ASTMatchersInternal.cpp:485
SelectorExtras.h
clang::ObjCMethodDecl
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:138
clang::NamedDecl::getIdentifier
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:244
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:110
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:168
State
LineState State
Definition: UnwrappedLineFormatter.cpp:932
Checker.h
clang::ObjCMethodCall::getReceiverInterface
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Definition: CallEvent.h:1002
CheckerManager.h
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:53
clang::ObjCMethodCall
Represents any expression that calls an Objective-C method.
Definition: CallEvent.h:938
clang::ObjCInterfaceDecl
Represents an ObjC class declaration.
Definition: DeclObjC.h:1186
clang::ObjCInterfaceDecl::getSuperClass
ObjCInterfaceDecl * getSuperClass() const
Definition: DeclObjC.cpp:337
BuiltinCheckerRegistration.h
REGISTER_MAP_WITH_PROGRAMSTATE
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Definition: ProgramStateTrait.h:84
clang::getKeywordSelector
static Selector getKeywordSelector(ASTContext &Ctx, IdentifierInfos *... IIs)
Definition: SelectorExtras.h:17
clang::Type::isAnyPointerType
bool isAnyPointerType() const
Definition: Type.h:6508
clang::IdentifierInfo::getName
StringRef getName() const
Return the actual identifier string.
Definition: IdentifierTable.h:155
clang::ObjCMethodCall::getSelector
Selector getSelector() const
Definition: CallEvent.h:986
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
clang::ento::getNullabilityAnnotation
Nullability getNullabilityAnnotation(QualType Type)
Get nullability annotation for a given type.
Definition: CheckerHelpers.cpp:101
CheckerHelpers.h
CallEvent.h
CallEvent
CheckerContext.h