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