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