xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //== TrustNonnullChecker.cpp --------- API nullability modeling -*- C++ -*--==//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This checker adds nullability-related assumptions:
107330f729Sjoerg //
117330f729Sjoerg // 1. Methods annotated with _Nonnull
127330f729Sjoerg // which come from system headers actually return a non-null pointer.
137330f729Sjoerg //
147330f729Sjoerg // 2. NSDictionary key is non-null after the keyword subscript operation
157330f729Sjoerg // on read if and only if the resulting expression is non-null.
167330f729Sjoerg //
177330f729Sjoerg // 3. NSMutableDictionary index is non-null after a write operation.
187330f729Sjoerg //
197330f729Sjoerg //===----------------------------------------------------------------------===//
207330f729Sjoerg 
217330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
227330f729Sjoerg #include "clang/Analysis/SelectorExtras.h"
237330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
247330f729Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
257330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
267330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
277330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
287330f729Sjoerg 
297330f729Sjoerg using namespace clang;
307330f729Sjoerg using namespace ento;
317330f729Sjoerg 
327330f729Sjoerg /// Records implications between symbols.
337330f729Sjoerg /// The semantics is:
347330f729Sjoerg ///    (antecedent != 0) => (consequent != 0)
357330f729Sjoerg /// These implications are then read during the evaluation of the assumption,
367330f729Sjoerg /// and the appropriate antecedents are applied.
377330f729Sjoerg REGISTER_MAP_WITH_PROGRAMSTATE(NonNullImplicationMap, SymbolRef, SymbolRef)
387330f729Sjoerg 
397330f729Sjoerg /// The semantics is:
407330f729Sjoerg ///    (antecedent == 0) => (consequent == 0)
417330f729Sjoerg REGISTER_MAP_WITH_PROGRAMSTATE(NullImplicationMap, SymbolRef, SymbolRef)
427330f729Sjoerg 
437330f729Sjoerg namespace {
447330f729Sjoerg 
457330f729Sjoerg class TrustNonnullChecker : public Checker<check::PostCall,
467330f729Sjoerg                                            check::PostObjCMessage,
477330f729Sjoerg                                            check::DeadSymbols,
487330f729Sjoerg                                            eval::Assume> {
497330f729Sjoerg   // Do not try to iterate over symbols with higher complexity.
507330f729Sjoerg   static unsigned constexpr ComplexityThreshold = 10;
517330f729Sjoerg   Selector ObjectForKeyedSubscriptSel;
527330f729Sjoerg   Selector ObjectForKeySel;
537330f729Sjoerg   Selector SetObjectForKeyedSubscriptSel;
547330f729Sjoerg   Selector SetObjectForKeySel;
557330f729Sjoerg 
567330f729Sjoerg public:
TrustNonnullChecker(ASTContext & Ctx)577330f729Sjoerg   TrustNonnullChecker(ASTContext &Ctx)
587330f729Sjoerg       : ObjectForKeyedSubscriptSel(
597330f729Sjoerg             getKeywordSelector(Ctx, "objectForKeyedSubscript")),
607330f729Sjoerg         ObjectForKeySel(getKeywordSelector(Ctx, "objectForKey")),
617330f729Sjoerg         SetObjectForKeyedSubscriptSel(
627330f729Sjoerg             getKeywordSelector(Ctx, "setObject", "forKeyedSubscript")),
637330f729Sjoerg         SetObjectForKeySel(getKeywordSelector(Ctx, "setObject", "forKey")) {}
647330f729Sjoerg 
evalAssume(ProgramStateRef State,SVal Cond,bool Assumption) const657330f729Sjoerg   ProgramStateRef evalAssume(ProgramStateRef State,
667330f729Sjoerg                              SVal Cond,
677330f729Sjoerg                              bool Assumption) const {
687330f729Sjoerg     const SymbolRef CondS = Cond.getAsSymbol();
697330f729Sjoerg     if (!CondS || CondS->computeComplexity() > ComplexityThreshold)
707330f729Sjoerg       return State;
717330f729Sjoerg 
727330f729Sjoerg     for (auto B=CondS->symbol_begin(), E=CondS->symbol_end(); B != E; ++B) {
737330f729Sjoerg       const SymbolRef Antecedent = *B;
747330f729Sjoerg       State = addImplication(Antecedent, State, true);
757330f729Sjoerg       State = addImplication(Antecedent, State, false);
767330f729Sjoerg     }
777330f729Sjoerg 
787330f729Sjoerg     return State;
797330f729Sjoerg   }
807330f729Sjoerg 
checkPostCall(const CallEvent & Call,CheckerContext & C) const817330f729Sjoerg   void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
827330f729Sjoerg     // Only trust annotations for system headers for non-protocols.
837330f729Sjoerg     if (!Call.isInSystemHeader())
847330f729Sjoerg       return;
857330f729Sjoerg 
867330f729Sjoerg     ProgramStateRef State = C.getState();
877330f729Sjoerg 
887330f729Sjoerg     if (isNonNullPtr(Call, C))
897330f729Sjoerg       if (auto L = Call.getReturnValue().getAs<Loc>())
907330f729Sjoerg         State = State->assume(*L, /*assumption=*/true);
917330f729Sjoerg 
927330f729Sjoerg     C.addTransition(State);
937330f729Sjoerg   }
947330f729Sjoerg 
checkPostObjCMessage(const ObjCMethodCall & Msg,CheckerContext & C) const957330f729Sjoerg   void checkPostObjCMessage(const ObjCMethodCall &Msg,
967330f729Sjoerg                             CheckerContext &C) const {
977330f729Sjoerg     const ObjCInterfaceDecl *ID = Msg.getReceiverInterface();
987330f729Sjoerg     if (!ID)
997330f729Sjoerg       return;
1007330f729Sjoerg 
1017330f729Sjoerg     ProgramStateRef State = C.getState();
1027330f729Sjoerg 
1037330f729Sjoerg     // Index to setter for NSMutableDictionary is assumed to be non-null,
1047330f729Sjoerg     // as an exception is thrown otherwise.
1057330f729Sjoerg     if (interfaceHasSuperclass(ID, "NSMutableDictionary") &&
1067330f729Sjoerg         (Msg.getSelector() == SetObjectForKeyedSubscriptSel ||
1077330f729Sjoerg          Msg.getSelector() == SetObjectForKeySel)) {
1087330f729Sjoerg       if (auto L = Msg.getArgSVal(1).getAs<Loc>())
1097330f729Sjoerg         State = State->assume(*L, /*assumption=*/true);
1107330f729Sjoerg     }
1117330f729Sjoerg 
1127330f729Sjoerg     // Record an implication: index is non-null if the output is non-null.
1137330f729Sjoerg     if (interfaceHasSuperclass(ID, "NSDictionary") &&
1147330f729Sjoerg         (Msg.getSelector() == ObjectForKeyedSubscriptSel ||
1157330f729Sjoerg          Msg.getSelector() == ObjectForKeySel)) {
1167330f729Sjoerg       SymbolRef ArgS = Msg.getArgSVal(0).getAsSymbol();
1177330f729Sjoerg       SymbolRef RetS = Msg.getReturnValue().getAsSymbol();
1187330f729Sjoerg 
1197330f729Sjoerg       if (ArgS && RetS) {
1207330f729Sjoerg         // Emulate an implication: the argument is non-null if
1217330f729Sjoerg         // the return value is non-null.
1227330f729Sjoerg         State = State->set<NonNullImplicationMap>(RetS, ArgS);
1237330f729Sjoerg 
1247330f729Sjoerg         // Conversely, when the argument is null, the return value
1257330f729Sjoerg         // is definitely null.
1267330f729Sjoerg         State = State->set<NullImplicationMap>(ArgS, RetS);
1277330f729Sjoerg       }
1287330f729Sjoerg     }
1297330f729Sjoerg 
1307330f729Sjoerg     C.addTransition(State);
1317330f729Sjoerg   }
1327330f729Sjoerg 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const1337330f729Sjoerg   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const {
1347330f729Sjoerg     ProgramStateRef State = C.getState();
1357330f729Sjoerg 
1367330f729Sjoerg     State = dropDeadFromGDM<NullImplicationMap>(SymReaper, State);
1377330f729Sjoerg     State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper, State);
1387330f729Sjoerg 
1397330f729Sjoerg     C.addTransition(State);
1407330f729Sjoerg   }
1417330f729Sjoerg 
1427330f729Sjoerg private:
1437330f729Sjoerg 
1447330f729Sjoerg   /// \returns State with GDM \p MapName where all dead symbols were
1457330f729Sjoerg   // removed.
1467330f729Sjoerg   template <typename MapName>
dropDeadFromGDM(SymbolReaper & SymReaper,ProgramStateRef State) const1477330f729Sjoerg   ProgramStateRef dropDeadFromGDM(SymbolReaper &SymReaper,
1487330f729Sjoerg                                   ProgramStateRef State) const {
1497330f729Sjoerg     for (const std::pair<SymbolRef, SymbolRef> &P : State->get<MapName>())
1507330f729Sjoerg       if (!SymReaper.isLive(P.first) || !SymReaper.isLive(P.second))
1517330f729Sjoerg         State = State->remove<MapName>(P.first);
1527330f729Sjoerg     return State;
1537330f729Sjoerg   }
1547330f729Sjoerg 
1557330f729Sjoerg   /// \returns Whether we trust the result of the method call to be
1567330f729Sjoerg   /// a non-null pointer.
isNonNullPtr(const CallEvent & Call,CheckerContext & C) const1577330f729Sjoerg   bool isNonNullPtr(const CallEvent &Call, CheckerContext &C) const {
1587330f729Sjoerg     QualType ExprRetType = Call.getResultType();
1597330f729Sjoerg     if (!ExprRetType->isAnyPointerType())
1607330f729Sjoerg       return false;
1617330f729Sjoerg 
1627330f729Sjoerg     if (getNullabilityAnnotation(ExprRetType) == Nullability::Nonnull)
1637330f729Sjoerg       return true;
1647330f729Sjoerg 
1657330f729Sjoerg     // The logic for ObjC instance method calls is more complicated,
1667330f729Sjoerg     // as the return value is nil when the receiver is nil.
1677330f729Sjoerg     if (!isa<ObjCMethodCall>(&Call))
1687330f729Sjoerg       return false;
1697330f729Sjoerg 
1707330f729Sjoerg     const auto *MCall = cast<ObjCMethodCall>(&Call);
1717330f729Sjoerg     const ObjCMethodDecl *MD = MCall->getDecl();
1727330f729Sjoerg 
1737330f729Sjoerg     // Distrust protocols.
1747330f729Sjoerg     if (isa<ObjCProtocolDecl>(MD->getDeclContext()))
1757330f729Sjoerg       return false;
1767330f729Sjoerg 
1777330f729Sjoerg     QualType DeclRetType = MD->getReturnType();
1787330f729Sjoerg     if (getNullabilityAnnotation(DeclRetType) != Nullability::Nonnull)
1797330f729Sjoerg       return false;
1807330f729Sjoerg 
1817330f729Sjoerg     // For class messages it is sufficient for the declaration to be
1827330f729Sjoerg     // annotated _Nonnull.
1837330f729Sjoerg     if (!MCall->isInstanceMessage())
1847330f729Sjoerg       return true;
1857330f729Sjoerg 
1867330f729Sjoerg     // Alternatively, the analyzer could know that the receiver is not null.
1877330f729Sjoerg     SVal Receiver = MCall->getReceiverSVal();
1887330f729Sjoerg     ConditionTruthVal TV = C.getState()->isNonNull(Receiver);
1897330f729Sjoerg     if (TV.isConstrainedTrue())
1907330f729Sjoerg       return true;
1917330f729Sjoerg 
1927330f729Sjoerg     return false;
1937330f729Sjoerg   }
1947330f729Sjoerg 
1957330f729Sjoerg   /// \return Whether \p ID has a superclass by the name \p ClassName.
interfaceHasSuperclass(const ObjCInterfaceDecl * ID,StringRef ClassName) const1967330f729Sjoerg   bool interfaceHasSuperclass(const ObjCInterfaceDecl *ID,
1977330f729Sjoerg                          StringRef ClassName) const {
1987330f729Sjoerg     if (ID->getIdentifier()->getName() == ClassName)
1997330f729Sjoerg       return true;
2007330f729Sjoerg 
2017330f729Sjoerg     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
2027330f729Sjoerg       return interfaceHasSuperclass(Super, ClassName);
2037330f729Sjoerg 
2047330f729Sjoerg     return false;
2057330f729Sjoerg   }
2067330f729Sjoerg 
2077330f729Sjoerg 
2087330f729Sjoerg   /// \return a state with an optional implication added (if exists)
2097330f729Sjoerg   /// from a map of recorded implications.
2107330f729Sjoerg   /// If \p Negated is true, checks NullImplicationMap, and assumes
2117330f729Sjoerg   /// the negation of \p Antecedent.
2127330f729Sjoerg   /// Checks NonNullImplicationMap and assumes \p Antecedent otherwise.
addImplication(SymbolRef Antecedent,ProgramStateRef InputState,bool Negated) const2137330f729Sjoerg   ProgramStateRef addImplication(SymbolRef Antecedent,
2147330f729Sjoerg                                  ProgramStateRef InputState,
2157330f729Sjoerg                                  bool Negated) const {
2167330f729Sjoerg     if (!InputState)
2177330f729Sjoerg       return nullptr;
2187330f729Sjoerg     SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
2197330f729Sjoerg     const SymbolRef *Consequent =
2207330f729Sjoerg         Negated ? InputState->get<NonNullImplicationMap>(Antecedent)
2217330f729Sjoerg                 : InputState->get<NullImplicationMap>(Antecedent);
2227330f729Sjoerg     if (!Consequent)
2237330f729Sjoerg       return InputState;
2247330f729Sjoerg 
2257330f729Sjoerg     SVal AntecedentV = SVB.makeSymbolVal(Antecedent);
2267330f729Sjoerg     ProgramStateRef State = InputState;
2277330f729Sjoerg 
2287330f729Sjoerg     if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
2297330f729Sjoerg         || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
2307330f729Sjoerg       SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
2317330f729Sjoerg       State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
2327330f729Sjoerg       if (!State)
2337330f729Sjoerg         return nullptr;
2347330f729Sjoerg 
2357330f729Sjoerg       // Drop implications from the map.
2367330f729Sjoerg       if (Negated) {
2377330f729Sjoerg         State = State->remove<NonNullImplicationMap>(Antecedent);
2387330f729Sjoerg         State = State->remove<NullImplicationMap>(*Consequent);
2397330f729Sjoerg       } else {
2407330f729Sjoerg         State = State->remove<NullImplicationMap>(Antecedent);
2417330f729Sjoerg         State = State->remove<NonNullImplicationMap>(*Consequent);
2427330f729Sjoerg       }
2437330f729Sjoerg     }
2447330f729Sjoerg 
2457330f729Sjoerg     return State;
2467330f729Sjoerg   }
2477330f729Sjoerg };
2487330f729Sjoerg 
2497330f729Sjoerg } // end empty namespace
2507330f729Sjoerg 
registerTrustNonnullChecker(CheckerManager & Mgr)2517330f729Sjoerg void ento::registerTrustNonnullChecker(CheckerManager &Mgr) {
2527330f729Sjoerg   Mgr.registerChecker<TrustNonnullChecker>(Mgr.getASTContext());
2537330f729Sjoerg }
2547330f729Sjoerg 
shouldRegisterTrustNonnullChecker(const CheckerManager & mgr)255*e038c9c4Sjoerg bool ento::shouldRegisterTrustNonnullChecker(const CheckerManager &mgr) {
2567330f729Sjoerg   return true;
2577330f729Sjoerg }
258