r254007 - [analyzer] Pass value expression for inlined defensive checks when binding null to nonnull.

Devin Coughlin via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 24 11:15:11 PST 2015


Author: dcoughlin
Date: Tue Nov 24 13:15:11 2015
New Revision: 254007

URL: http://llvm.org/viewvc/llvm-project?rev=254007&view=rev
Log:
[analyzer] Pass value expression for inlined defensive checks when binding null to nonnull.

The nullability checker was not suppressing false positives resulting from
inlined defensive checks when null was bound to a nonnull variable because it
was passing the entire bind statement rather than the value expression to
trackNullOrUndefValue().

This commit changes that checker to synactically match on the bind statement to
extract the value expression so it can be passed to trackNullOrUndefValue().

rdar://problem/23575439

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=254007&r1=254006&r2=254007&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp Tue Nov 24 13:15:11 2015
@@ -862,6 +862,30 @@ void NullabilityChecker::checkPostStmt(c
   }
 }
 
+/// For a given statement performing a bind, attempt to syntactically
+/// match the expression resulting in the bound value.
+static const Expr * matchValueExprForBind(const Stmt *S) {
+  // For `x = e` the value expression is the right-hand side.
+  if (auto *BinOp = dyn_cast<BinaryOperator>(S)) {
+    if (BinOp->getOpcode() == BO_Assign)
+      return BinOp->getRHS();
+  }
+
+  // For `int x = e` the value expression is the initializer.
+  if (auto *DS = dyn_cast<DeclStmt>(S))  {
+    if (DS->isSingleDecl()) {
+      auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+      if (!VD)
+        return nullptr;
+
+      if (const Expr *Init = VD->getInit())
+        return Init;
+    }
+  }
+
+  return nullptr;
+}
+
 /// 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,
@@ -898,8 +922,13 @@ void NullabilityChecker::checkBind(SVal
     ExplodedNode *N = C.generateErrorNode(State, &Tag);
     if (!N)
       return;
+
+    const Stmt *ValueExpr = matchValueExprForBind(S);
+    if (!ValueExpr)
+      ValueExpr = S;
+
     reportBugIfPreconditionHolds(ErrorKind::NilAssignedToNonnull, N, nullptr, C,
-                                 S);
+                                 ValueExpr);
     return;
   }
   // Intentionally missing case: '0' is bound to a reference. It is handled by

Modified: cfe/trunk/test/Analysis/nullability.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nullability.mm?rev=254007&r1=254006&r2=254007&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/nullability.mm (original)
+++ cfe/trunk/test/Analysis/nullability.mm Tue Nov 24 13:15:11 2015
@@ -238,6 +238,19 @@ Dummy *_Nonnull testDefensiveInlineCheck
   case 3: inlinedUnspecified(p); break;
   }
   if (getRandom())
-    takesNonnull(p);
+    takesNonnull(p);  // no-warning
+
+  if (getRandom()) {
+    Dummy *_Nonnull varWithInitializer = p; // no-warning
+
+     Dummy *_Nonnull var1WithInitializer = p,  // no-warning
+           *_Nonnull var2WithInitializer = p;  // no-warning
+  }
+
+  if (getRandom()) {
+    Dummy *_Nonnull varWithoutInitializer;
+    varWithoutInitializer = p; // no-warning
+  }
+
   return p;
 }




More information about the cfe-commits mailing list