Author: dcoughlin Date: Tue Dec 29 17:44:19 2015 New Revision: 256603 URL: http://llvm.org/viewvc/llvm-project?rev=256603&view=rev Log: [analyzer] Suppress nullability warning for _Nonnull locals zero-initialized by ObjC ARC.
Prevent the analyzer from warning when a _Nonnnull local variable is implicitly zero-initialized because of Objective-C automated reference counting. This avoids false positives in cases where a _Nonnull local variable cannot be initialized with an initialization expression, such as: NSString * _Nonnull s; // no-warning @autoreleasepool { s = ...; } The nullability checker will still warn when a _Nonnull local variable is explicitly initialized with nil. This suppression introduces the potential for false negatives if the local variable is used before it is assigned a _Nonnull value. Based on a discussion with Anna Zaks, Jordan Rose, and John McCall, I've added a FIXME to treat implicitly zero-initialized _Nonnull locals as uninitialized in Sema's UninitializedValues analysis to avoid these false negatives. rdar://problem/23522311 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp cfe/trunk/test/Analysis/nullability.mm Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp?rev=256603&r1=256602&r2=256603&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp Tue Dec 29 17:44:19 2015 @@ -897,6 +897,48 @@ static const Expr * matchValueExprForBin return nullptr; } +/// Returns true if \param S is a DeclStmt for a local variable that +/// ObjC automated reference counting initialized with zero. +static bool isARCNilInitializedLocal(CheckerContext &C, const Stmt *S) { + // We suppress diagnostics for ARC zero-initialized _Nonnull locals. This + // prevents false positives when a _Nonnull local variable cannot be + // initialized with an initialization expression: + // NSString * _Nonnull s; // no-warning + // @autoreleasepool { + // s = ... + // } + // + // FIXME: We should treat implicitly zero-initialized _Nonnull locals as + // uninitialized in Sema's UninitializedValues analysis to warn when a use of + // the zero-initialized definition will unexpectedly yield nil. + + // Locals are only zero-initialized when automated reference counting + // is turned on. + if (!C.getASTContext().getLangOpts().ObjCAutoRefCount) + return false; + + auto *DS = dyn_cast<DeclStmt>(S); + if (!DS || !DS->isSingleDecl()) + return false; + + auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); + if (!VD) + return false; + + // Sema only zero-initializes locals with ObjCLifetimes. + if(!VD->getType().getQualifiers().hasObjCLifetime()) + return false; + + const Expr *Init = VD->getInit(); + assert(Init && "ObjC local under ARC without initializer"); + + // Return false if the local is explicitly initialized (e.g., with '= nil'). + if (!isa<ImplicitValueInitExpr>(Init)) + return false; + + return true; +} + /// Propagate the nullability information through binds and warn when nullable /// pointer or null symbol is assigned to a pointer with a nonnull type. void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S, @@ -928,7 +970,8 @@ void NullabilityChecker::checkBind(SVal if (Filter.CheckNullPassedToNonnull && RhsNullness == NullConstraint::IsNull && ValNullability != Nullability::Nonnull && - LocNullability == Nullability::Nonnull) { + LocNullability == Nullability::Nonnull && + !isARCNilInitializedLocal(C, S)) { static CheckerProgramPointTag Tag(this, "NullPassedToNonnull"); ExplodedNode *N = C.generateErrorNode(State, &Tag); if (!N) Modified: cfe/trunk/test/Analysis/nullability.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nullability.mm?rev=256603&r1=256602&r2=256603&view=diff ============================================================================== --- cfe/trunk/test/Analysis/nullability.mm (original) +++ cfe/trunk/test/Analysis/nullability.mm Tue Dec 29 17:44:19 2015 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s +// RUN: %clang_cc1 -fobjc-arc -analyze -analyzer-checker=core,nullability -verify %s #define nil 0 #define BOOL int @@ -278,3 +278,12 @@ Dummy *_Nonnull testDefensiveInlineCheck return p; } + +void testObjCARCImplicitZeroInitialization() { + TestObject * _Nonnull implicitlyZeroInitialized; // no-warning + implicitlyZeroInitialized = getNonnullTestObject(); +} + +void testObjCARCExplicitZeroInitialization() { + TestObject * _Nonnull explicitlyZeroInitialized = nil; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits