static Nullability getReceiverNullability(const ObjCMethodCall &M, ProgramStateRef State) { if (M.isReceiverSelfOrSuper()) { // For super and super class receivers we assume that the receiver is // nonnull. return Nullability::Nonnull; } // Otherwise look up nullability in the state. SVal Receiver = M.getReceiverSVal(); if (auto DefOrUnknown = Receiver.getAs<DefinedOrUnknownSVal>()) { // If the receiver is constrained to be nonnull, assume that it is nonnull // regardless of its type. NullConstraint Nullness = getNullConstraint(*DefOrUnknown, State); if (Nullness == NullConstraint::IsNotNull) return Nullability::Nonnull; } auto ValueRegionSVal = Receiver.getAs<loc::MemRegionVal>(); if (ValueRegionSVal) { const MemRegion *SelfRegion = ValueRegionSVal->getRegion(); assert(SelfRegion); const NullabilityState *TrackedSelfNullability = State->get<NullabilityMap>(SelfRegion); if (TrackedSelfNullability) return TrackedSelfNullability->getValue(); } return Nullability::Unspecified; }
/// If we are in -dealloc or -dealloc is on the stack, handle the call if it is /// a release or a nilling-out property setter. void ObjCDeallocChecker::checkPreObjCMessage( const ObjCMethodCall &M, CheckerContext &C) const { // Only run if -dealloc is on the stack. SVal DeallocedInstance; if (!instanceDeallocIsOnStack(C, DeallocedInstance)) return; SymbolRef ReleasedValue = nullptr; if (M.getSelector() == ReleaseSel) { ReleasedValue = M.getReceiverSVal().getAsSymbol(); } else if (M.getSelector() == DeallocSel && !M.isReceiverSelfOrSuper()) { if (diagnoseMistakenDealloc(M.getReceiverSVal().getAsSymbol(), M, C)) return; } if (ReleasedValue) { // An instance variable symbol was released with -release: // [_property release]; if (diagnoseExtraRelease(ReleasedValue,M, C)) return; } else { // An instance variable symbol was released nilling out its property: // self.property = nil; ReleasedValue = getValueReleasedByNillingOut(M, C); } if (!ReleasedValue) return; transitionToReleaseValue(C, ReleasedValue); }
void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const { ProgramStateRef State = C.getState(); if (!Initialized) { ASTContext &Ctx = C.getASTContext(); ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx); ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx); NullSelector = GetNullarySelector("null", Ctx); } // Check the receiver type. if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) { // Assume that object returned from '[self init]' or '[super init]' is not // 'nil' if we are processing an inlined function/method. // // A defensive callee will (and should) check if the object returned by // '[super init]' is 'nil' before doing it's own initialization. However, // since 'nil' is rarely returned in practice, we should not warn when the // caller to the defensive constructor uses the object in contexts where // 'nil' is not accepted. if (!C.inTopFrame() && M.getDecl() && M.getDecl()->getMethodFamily() == OMF_init && M.isReceiverSelfOrSuper()) { State = assumeExprIsNonNull(M.getOriginExpr(), State, C); } FoundationClass Cl = findKnownClass(Interface); // Objects returned from // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript] // are never 'nil'. if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) { Selector Sel = M.getSelector(); if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) { // Go ahead and assume the value is non-nil. State = assumeExprIsNonNull(M.getOriginExpr(), State, C); } } // Objects returned from [NSNull null] are not nil. if (Cl == FC_NSNull) { if (M.getSelector() == NullSelector) { // Go ahead and assume the value is non-nil. State = assumeExprIsNonNull(M.getOriginExpr(), State, C); } } } C.addTransition(State); }