xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //== TrustNonnullChecker.cpp --------- API nullability modeling -*- C++ -*--==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This checker adds nullability-related assumptions:
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // 1. Methods annotated with _Nonnull
120b57cec5SDimitry Andric // which come from system headers actually return a non-null pointer.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric // 2. NSDictionary key is non-null after the keyword subscript operation
150b57cec5SDimitry Andric // on read if and only if the resulting expression is non-null.
160b57cec5SDimitry Andric //
170b57cec5SDimitry Andric // 3. NSMutableDictionary index is non-null after a write operation.
180b57cec5SDimitry Andric //
190b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
220b57cec5SDimitry Andric #include "clang/Analysis/SelectorExtras.h"
230b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
240b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
250b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
260b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
270b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace clang;
300b57cec5SDimitry Andric using namespace ento;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric /// Records implications between symbols.
330b57cec5SDimitry Andric /// The semantics is:
340b57cec5SDimitry Andric ///    (antecedent != 0) => (consequent != 0)
350b57cec5SDimitry Andric /// These implications are then read during the evaluation of the assumption,
360b57cec5SDimitry Andric /// and the appropriate antecedents are applied.
370b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(NonNullImplicationMap, SymbolRef, SymbolRef)
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric /// The semantics is:
400b57cec5SDimitry Andric ///    (antecedent == 0) => (consequent == 0)
410b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(NullImplicationMap, SymbolRef, SymbolRef)
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric namespace {
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric class TrustNonnullChecker : public Checker<check::PostCall,
460b57cec5SDimitry Andric                                            check::PostObjCMessage,
470b57cec5SDimitry Andric                                            check::DeadSymbols,
480b57cec5SDimitry Andric                                            eval::Assume> {
490b57cec5SDimitry Andric   // Do not try to iterate over symbols with higher complexity.
500b57cec5SDimitry Andric   static unsigned constexpr ComplexityThreshold = 10;
510b57cec5SDimitry Andric   Selector ObjectForKeyedSubscriptSel;
520b57cec5SDimitry Andric   Selector ObjectForKeySel;
530b57cec5SDimitry Andric   Selector SetObjectForKeyedSubscriptSel;
540b57cec5SDimitry Andric   Selector SetObjectForKeySel;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric public:
TrustNonnullChecker(ASTContext & Ctx)570b57cec5SDimitry Andric   TrustNonnullChecker(ASTContext &Ctx)
580b57cec5SDimitry Andric       : ObjectForKeyedSubscriptSel(
590b57cec5SDimitry Andric             getKeywordSelector(Ctx, "objectForKeyedSubscript")),
600b57cec5SDimitry Andric         ObjectForKeySel(getKeywordSelector(Ctx, "objectForKey")),
610b57cec5SDimitry Andric         SetObjectForKeyedSubscriptSel(
620b57cec5SDimitry Andric             getKeywordSelector(Ctx, "setObject", "forKeyedSubscript")),
630b57cec5SDimitry Andric         SetObjectForKeySel(getKeywordSelector(Ctx, "setObject", "forKey")) {}
640b57cec5SDimitry Andric 
evalAssume(ProgramStateRef State,SVal Cond,bool Assumption) const650b57cec5SDimitry Andric   ProgramStateRef evalAssume(ProgramStateRef State,
660b57cec5SDimitry Andric                              SVal Cond,
670b57cec5SDimitry Andric                              bool Assumption) const {
680b57cec5SDimitry Andric     const SymbolRef CondS = Cond.getAsSymbol();
690b57cec5SDimitry Andric     if (!CondS || CondS->computeComplexity() > ComplexityThreshold)
700b57cec5SDimitry Andric       return State;
710b57cec5SDimitry Andric 
72*06c3fb27SDimitry Andric     for (SymbolRef Antecedent : CondS->symbols()) {
730b57cec5SDimitry Andric       State = addImplication(Antecedent, State, true);
740b57cec5SDimitry Andric       State = addImplication(Antecedent, State, false);
750b57cec5SDimitry Andric     }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric     return State;
780b57cec5SDimitry Andric   }
790b57cec5SDimitry Andric 
checkPostCall(const CallEvent & Call,CheckerContext & C) const800b57cec5SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
810b57cec5SDimitry Andric     // Only trust annotations for system headers for non-protocols.
820b57cec5SDimitry Andric     if (!Call.isInSystemHeader())
830b57cec5SDimitry Andric       return;
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     ProgramStateRef State = C.getState();
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric     if (isNonNullPtr(Call, C))
880b57cec5SDimitry Andric       if (auto L = Call.getReturnValue().getAs<Loc>())
890b57cec5SDimitry Andric         State = State->assume(*L, /*assumption=*/true);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric     C.addTransition(State);
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric 
checkPostObjCMessage(const ObjCMethodCall & Msg,CheckerContext & C) const940b57cec5SDimitry Andric   void checkPostObjCMessage(const ObjCMethodCall &Msg,
950b57cec5SDimitry Andric                             CheckerContext &C) const {
960b57cec5SDimitry Andric     const ObjCInterfaceDecl *ID = Msg.getReceiverInterface();
970b57cec5SDimitry Andric     if (!ID)
980b57cec5SDimitry Andric       return;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric     ProgramStateRef State = C.getState();
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric     // Index to setter for NSMutableDictionary is assumed to be non-null,
1030b57cec5SDimitry Andric     // as an exception is thrown otherwise.
1040b57cec5SDimitry Andric     if (interfaceHasSuperclass(ID, "NSMutableDictionary") &&
1050b57cec5SDimitry Andric         (Msg.getSelector() == SetObjectForKeyedSubscriptSel ||
1060b57cec5SDimitry Andric          Msg.getSelector() == SetObjectForKeySel)) {
1070b57cec5SDimitry Andric       if (auto L = Msg.getArgSVal(1).getAs<Loc>())
1080b57cec5SDimitry Andric         State = State->assume(*L, /*assumption=*/true);
1090b57cec5SDimitry Andric     }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric     // Record an implication: index is non-null if the output is non-null.
1120b57cec5SDimitry Andric     if (interfaceHasSuperclass(ID, "NSDictionary") &&
1130b57cec5SDimitry Andric         (Msg.getSelector() == ObjectForKeyedSubscriptSel ||
1140b57cec5SDimitry Andric          Msg.getSelector() == ObjectForKeySel)) {
1150b57cec5SDimitry Andric       SymbolRef ArgS = Msg.getArgSVal(0).getAsSymbol();
1160b57cec5SDimitry Andric       SymbolRef RetS = Msg.getReturnValue().getAsSymbol();
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric       if (ArgS && RetS) {
1190b57cec5SDimitry Andric         // Emulate an implication: the argument is non-null if
1200b57cec5SDimitry Andric         // the return value is non-null.
1210b57cec5SDimitry Andric         State = State->set<NonNullImplicationMap>(RetS, ArgS);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric         // Conversely, when the argument is null, the return value
1240b57cec5SDimitry Andric         // is definitely null.
1250b57cec5SDimitry Andric         State = State->set<NullImplicationMap>(ArgS, RetS);
1260b57cec5SDimitry Andric       }
1270b57cec5SDimitry Andric     }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric     C.addTransition(State);
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const1320b57cec5SDimitry Andric   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const {
1330b57cec5SDimitry Andric     ProgramStateRef State = C.getState();
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric     State = dropDeadFromGDM<NullImplicationMap>(SymReaper, State);
1360b57cec5SDimitry Andric     State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper, State);
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric     C.addTransition(State);
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric private:
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   /// \returns State with GDM \p MapName where all dead symbols were
1440b57cec5SDimitry Andric   // removed.
1450b57cec5SDimitry Andric   template <typename MapName>
dropDeadFromGDM(SymbolReaper & SymReaper,ProgramStateRef State) const1460b57cec5SDimitry Andric   ProgramStateRef dropDeadFromGDM(SymbolReaper &SymReaper,
1470b57cec5SDimitry Andric                                   ProgramStateRef State) const {
1480b57cec5SDimitry Andric     for (const std::pair<SymbolRef, SymbolRef> &P : State->get<MapName>())
1490b57cec5SDimitry Andric       if (!SymReaper.isLive(P.first) || !SymReaper.isLive(P.second))
1500b57cec5SDimitry Andric         State = State->remove<MapName>(P.first);
1510b57cec5SDimitry Andric     return State;
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   /// \returns Whether we trust the result of the method call to be
1550b57cec5SDimitry Andric   /// a non-null pointer.
isNonNullPtr(const CallEvent & Call,CheckerContext & C) const1560b57cec5SDimitry Andric   bool isNonNullPtr(const CallEvent &Call, CheckerContext &C) const {
1570b57cec5SDimitry Andric     QualType ExprRetType = Call.getResultType();
1580b57cec5SDimitry Andric     if (!ExprRetType->isAnyPointerType())
1590b57cec5SDimitry Andric       return false;
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric     if (getNullabilityAnnotation(ExprRetType) == Nullability::Nonnull)
1620b57cec5SDimitry Andric       return true;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric     // The logic for ObjC instance method calls is more complicated,
1650b57cec5SDimitry Andric     // as the return value is nil when the receiver is nil.
1660b57cec5SDimitry Andric     if (!isa<ObjCMethodCall>(&Call))
1670b57cec5SDimitry Andric       return false;
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric     const auto *MCall = cast<ObjCMethodCall>(&Call);
1700b57cec5SDimitry Andric     const ObjCMethodDecl *MD = MCall->getDecl();
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric     // Distrust protocols.
1730b57cec5SDimitry Andric     if (isa<ObjCProtocolDecl>(MD->getDeclContext()))
1740b57cec5SDimitry Andric       return false;
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric     QualType DeclRetType = MD->getReturnType();
1770b57cec5SDimitry Andric     if (getNullabilityAnnotation(DeclRetType) != Nullability::Nonnull)
1780b57cec5SDimitry Andric       return false;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric     // For class messages it is sufficient for the declaration to be
1810b57cec5SDimitry Andric     // annotated _Nonnull.
1820b57cec5SDimitry Andric     if (!MCall->isInstanceMessage())
1830b57cec5SDimitry Andric       return true;
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric     // Alternatively, the analyzer could know that the receiver is not null.
1860b57cec5SDimitry Andric     SVal Receiver = MCall->getReceiverSVal();
1870b57cec5SDimitry Andric     ConditionTruthVal TV = C.getState()->isNonNull(Receiver);
1880b57cec5SDimitry Andric     if (TV.isConstrainedTrue())
1890b57cec5SDimitry Andric       return true;
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     return false;
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   /// \return Whether \p ID has a superclass by the name \p ClassName.
interfaceHasSuperclass(const ObjCInterfaceDecl * ID,StringRef ClassName) const1950b57cec5SDimitry Andric   bool interfaceHasSuperclass(const ObjCInterfaceDecl *ID,
1960b57cec5SDimitry Andric                          StringRef ClassName) const {
1970b57cec5SDimitry Andric     if (ID->getIdentifier()->getName() == ClassName)
1980b57cec5SDimitry Andric       return true;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric     if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
2010b57cec5SDimitry Andric       return interfaceHasSuperclass(Super, ClassName);
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric     return false;
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   /// \return a state with an optional implication added (if exists)
2080b57cec5SDimitry Andric   /// from a map of recorded implications.
2090b57cec5SDimitry Andric   /// If \p Negated is true, checks NullImplicationMap, and assumes
2100b57cec5SDimitry Andric   /// the negation of \p Antecedent.
2110b57cec5SDimitry Andric   /// Checks NonNullImplicationMap and assumes \p Antecedent otherwise.
addImplication(SymbolRef Antecedent,ProgramStateRef InputState,bool Negated) const2120b57cec5SDimitry Andric   ProgramStateRef addImplication(SymbolRef Antecedent,
2130b57cec5SDimitry Andric                                  ProgramStateRef InputState,
2140b57cec5SDimitry Andric                                  bool Negated) const {
2150b57cec5SDimitry Andric     if (!InputState)
2160b57cec5SDimitry Andric       return nullptr;
2170b57cec5SDimitry Andric     SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
2180b57cec5SDimitry Andric     const SymbolRef *Consequent =
2190b57cec5SDimitry Andric         Negated ? InputState->get<NonNullImplicationMap>(Antecedent)
2200b57cec5SDimitry Andric                 : InputState->get<NullImplicationMap>(Antecedent);
2210b57cec5SDimitry Andric     if (!Consequent)
2220b57cec5SDimitry Andric       return InputState;
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     SVal AntecedentV = SVB.makeSymbolVal(Antecedent);
2250b57cec5SDimitry Andric     ProgramStateRef State = InputState;
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric     if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
2280b57cec5SDimitry Andric         || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
2290b57cec5SDimitry Andric       SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
2300b57cec5SDimitry Andric       State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
2310b57cec5SDimitry Andric       if (!State)
2320b57cec5SDimitry Andric         return nullptr;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric       // Drop implications from the map.
2350b57cec5SDimitry Andric       if (Negated) {
2360b57cec5SDimitry Andric         State = State->remove<NonNullImplicationMap>(Antecedent);
2370b57cec5SDimitry Andric         State = State->remove<NullImplicationMap>(*Consequent);
2380b57cec5SDimitry Andric       } else {
2390b57cec5SDimitry Andric         State = State->remove<NullImplicationMap>(Antecedent);
2400b57cec5SDimitry Andric         State = State->remove<NonNullImplicationMap>(*Consequent);
2410b57cec5SDimitry Andric       }
2420b57cec5SDimitry Andric     }
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric     return State;
2450b57cec5SDimitry Andric   }
2460b57cec5SDimitry Andric };
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric } // end empty namespace
2490b57cec5SDimitry Andric 
registerTrustNonnullChecker(CheckerManager & Mgr)2500b57cec5SDimitry Andric void ento::registerTrustNonnullChecker(CheckerManager &Mgr) {
2510b57cec5SDimitry Andric   Mgr.registerChecker<TrustNonnullChecker>(Mgr.getASTContext());
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric 
shouldRegisterTrustNonnullChecker(const CheckerManager & mgr)2545ffd83dbSDimitry Andric bool ento::shouldRegisterTrustNonnullChecker(const CheckerManager &mgr) {
2550b57cec5SDimitry Andric   return true;
2560b57cec5SDimitry Andric }
257