Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp
Line
Count
Source (jump to first uncovered line)
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
10
        SetObjectForKeySel(getKeywordSelector(Ctx, "setObject", "forKey")) {}
64
65
  ProgramStateRef evalAssume(ProgramStateRef State,
66
                             SVal Cond,
67
5.51k
                             bool Assumption) const {
68
5.51k
    const SymbolRef CondS = Cond.getAsSymbol();
69
5.51k
    if (!CondS || 
CondS->computeComplexity() > ComplexityThreshold1.88k
)
70
3.63k
      return State;
71
1.88k
72
5.85k
    
for (auto B=CondS->symbol_begin(), E=CondS->symbol_end(); 1.88k
B != E;
++B3.97k
) {
73
3.97k
      const SymbolRef Antecedent = *B;
74
3.97k
      State = addImplication(Antecedent, State, true);
75
3.97k
      State = addImplication(Antecedent, State, false);
76
3.97k
    }
77
1.88k
78
1.88k
    return State;
79
1.88k
  }
80
81
149
  void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
82
149
    // Only trust annotations for system headers for non-protocols.
83
149
    if (!Call.isInSystemHeader())
84
146
      return;
85
3
86
3
    ProgramStateRef State = C.getState();
87
3
88
3
    if (isNonNullPtr(Call, C))
89
0
      if (auto L = Call.getReturnValue().getAs<Loc>())
90
0
        State = State->assume(*L, /*assumption=*/true);
91
3
92
3
    C.addTransition(State);
93
3
  }
94
95
  void checkPostObjCMessage(const ObjCMethodCall &Msg,
96
0
                            CheckerContext &C) const {
97
0
    const ObjCInterfaceDecl *ID = Msg.getReceiverInterface();
98
0
    if (!ID)
99
0
      return;
100
0
101
0
    ProgramStateRef State = C.getState();
102
0
103
0
    // Index to setter for NSMutableDictionary is assumed to be non-null,
104
0
    // as an exception is thrown otherwise.
105
0
    if (interfaceHasSuperclass(ID, "NSMutableDictionary") &&
106
0
        (Msg.getSelector() == SetObjectForKeyedSubscriptSel ||
107
0
         Msg.getSelector() == SetObjectForKeySel)) {
108
0
      if (auto L = Msg.getArgSVal(1).getAs<Loc>())
109
0
        State = State->assume(*L, /*assumption=*/true);
110
0
    }
111
0
112
0
    // Record an implication: index is non-null if the output is non-null.
113
0
    if (interfaceHasSuperclass(ID, "NSDictionary") &&
114
0
        (Msg.getSelector() == ObjectForKeyedSubscriptSel ||
115
0
         Msg.getSelector() == ObjectForKeySel)) {
116
0
      SymbolRef ArgS = Msg.getArgSVal(0).getAsSymbol();
117
0
      SymbolRef RetS = Msg.getReturnValue().getAsSymbol();
118
0
119
0
      if (ArgS && RetS) {
120
0
        // Emulate an implication: the argument is non-null if
121
0
        // the return value is non-null.
122
0
        State = State->set<NonNullImplicationMap>(RetS, ArgS);
123
0
124
0
        // Conversely, when the argument is null, the return value
125
0
        // is definitely null.
126
0
        State = State->set<NullImplicationMap>(ArgS, RetS);
127
0
      }
128
0
    }
129
0
130
0
    C.addTransition(State);
131
0
  }
132
133
2.60k
  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const {
134
2.60k
    ProgramStateRef State = C.getState();
135
2.60k
136
2.60k
    State = dropDeadFromGDM<NullImplicationMap>(SymReaper, State);
137
2.60k
    State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper, State);
138
2.60k
139
2.60k
    C.addTransition(State);
140
2.60k
  }
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
5.21k
                                  ProgramStateRef State) const {
149
5.21k
    for (const std::pair<SymbolRef, SymbolRef> &P : State->get<MapName>())
150
0
      if (!SymReaper.isLive(P.first) || !SymReaper.isLive(P.second))
151
0
        State = State->remove<MapName>(P.first);
152
5.21k
    return State;
153
5.21k
  }
TrustNonnullChecker.cpp:llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const> (anonymous namespace)::TrustNonnullChecker::dropDeadFromGDM<(anonymous namespace)::NullImplicationMap>(clang::ento::SymbolReaper&, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>) const
Line
Count
Source
148
2.60k
                                  ProgramStateRef State) const {
149
2.60k
    for (const std::pair<SymbolRef, SymbolRef> &P : State->get<MapName>())
150
0
      if (!SymReaper.isLive(P.first) || !SymReaper.isLive(P.second))
151
0
        State = State->remove<MapName>(P.first);
152
2.60k
    return State;
153
2.60k
  }
TrustNonnullChecker.cpp:llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const> (anonymous namespace)::TrustNonnullChecker::dropDeadFromGDM<(anonymous namespace)::NonNullImplicationMap>(clang::ento::SymbolReaper&, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>) const
Line
Count
Source
148
2.60k
                                  ProgramStateRef State) const {
149
2.60k
    for (const std::pair<SymbolRef, SymbolRef> &P : State->get<MapName>())
150
0
      if (!SymReaper.isLive(P.first) || !SymReaper.isLive(P.second))
151
0
        State = State->remove<MapName>(P.first);
152
2.60k
    return State;
153
2.60k
  }
154
155
  /// \returns Whether we trust the result of the method call to be
156
  /// a non-null pointer.
157
3
  bool isNonNullPtr(const CallEvent &Call, CheckerContext &C) const {
158
3
    QualType ExprRetType = Call.getResultType();
159
3
    if (!ExprRetType->isAnyPointerType())
160
3
      return false;
161
0
162
0
    if (getNullabilityAnnotation(ExprRetType) == Nullability::Nonnull)
163
0
      return true;
164
0
165
0
    // The logic for ObjC instance method calls is more complicated,
166
0
    // as the return value is nil when the receiver is nil.
167
0
    if (!isa<ObjCMethodCall>(&Call))
168
0
      return false;
169
0
170
0
    const auto *MCall = cast<ObjCMethodCall>(&Call);
171
0
    const ObjCMethodDecl *MD = MCall->getDecl();
172
0
173
0
    // Distrust protocols.
174
0
    if (isa<ObjCProtocolDecl>(MD->getDeclContext()))
175
0
      return false;
176
0
177
0
    QualType DeclRetType = MD->getReturnType();
178
0
    if (getNullabilityAnnotation(DeclRetType) != Nullability::Nonnull)
179
0
      return false;
180
0
181
0
    // For class messages it is sufficient for the declaration to be
182
0
    // annotated _Nonnull.
183
0
    if (!MCall->isInstanceMessage())
184
0
      return true;
185
0
186
0
    // Alternatively, the analyzer could know that the receiver is not null.
187
0
    SVal Receiver = MCall->getReceiverSVal();
188
0
    ConditionTruthVal TV = C.getState()->isNonNull(Receiver);
189
0
    if (TV.isConstrainedTrue())
190
0
      return true;
191
0
192
0
    return false;
193
0
  }
194
195
  /// \return Whether \p ID has a superclass by the name \p ClassName.
196
  bool interfaceHasSuperclass(const ObjCInterfaceDecl *ID,
197
0
                         StringRef ClassName) const {
198
0
    if (ID->getIdentifier()->getName() == ClassName)
199
0
      return true;
200
0
201
0
    if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
202
0
      return interfaceHasSuperclass(Super, ClassName);
203
0
204
0
    return false;
205
0
  }
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
7.94k
                                 bool Negated) const {
216
7.94k
    if (!InputState)
217
0
      return nullptr;
218
7.94k
    SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
219
7.94k
    const SymbolRef *Consequent =
220
7.94k
        Negated ? 
InputState->get<NonNullImplicationMap>(Antecedent)3.97k
221
7.94k
                : 
InputState->get<NullImplicationMap>(Antecedent)3.97k
;
222
7.94k
    if (!Consequent)
223
7.94k
      return InputState;
224
0
225
0
    SVal AntecedentV = SVB.makeSymbolVal(Antecedent);
226
0
    ProgramStateRef State = InputState;
227
0
228
0
    if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
229
0
        || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
230
0
      SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
231
0
      State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
232
0
      if (!State)
233
0
        return nullptr;
234
0
235
0
      // Drop implications from the map.
236
0
      if (Negated) {
237
0
        State = State->remove<NonNullImplicationMap>(Antecedent);
238
0
        State = State->remove<NullImplicationMap>(*Consequent);
239
0
      } else {
240
0
        State = State->remove<NullImplicationMap>(Antecedent);
241
0
        State = State->remove<NonNullImplicationMap>(*Consequent);
242
0
      }
243
0
    }
244
0
245
0
    return State;
246
0
  }
247
};
248
249
} // end empty namespace
250
251
10
void ento::registerTrustNonnullChecker(CheckerManager &Mgr) {
252
10
  Mgr.registerChecker<TrustNonnullChecker>(Mgr.getASTContext());
253
10
}
254
255
10
bool ento::shouldRegisterTrustNonnullChecker(const LangOptions &LO) {
256
10
  return true;
257
10
}