]> granicus.if.org Git - clang/commitdiff
[analyzer] Nullability: Suppress return diagnostics in inlined functions.
authorDevin Coughlin <dcoughlin@apple.com>
Tue, 12 Apr 2016 19:29:52 +0000 (19:29 +0000)
committerDevin Coughlin <dcoughlin@apple.com>
Tue, 12 Apr 2016 19:29:52 +0000 (19:29 +0000)
The nullability checker can sometimes miss detecting nullability precondition
violations in inlined functions because the binding for the parameter
that violated the precondition becomes dead before the return:

int * _Nonnull callee(int * _Nonnull p2) {
  if (!p2)
    // p2 becomes dead here, so binding removed.
    return 0; // warning here because value stored in p2 is symbolic.
  else
   return p2;
}

int *caller(int * _Nonnull p1) {
  return callee(p1);
}

The fix, which is quite blunt, is to not warn about null returns in inlined
methods/functions. This won’t lose much coverage for ObjC because the analyzer
always analyzes each ObjC method at the top level in addition to inlined. It
*will* lose coverage for C — but there aren’t that many codebases with C
nullability annotations.

rdar://problem/25615050

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@266109 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
test/Analysis/nullability.mm

index 35620d33acf1974eab4a93a5f59330b91b60431f..d8a224ea2f458aa2aae18256b81bf482000083d6 100644 (file)
@@ -562,7 +562,8 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
   if (Filter.CheckNullReturnedFromNonnull &&
       NullReturnedFromNonNull &&
       RetExprTypeLevelNullability != Nullability::Nonnull &&
-      !InSuppressedMethodFamily) {
+      !InSuppressedMethodFamily &&
+      C.getLocationContext()->inTopFrame()) {
     static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
     ExplodedNode *N = C.generateErrorNode(State, &Tag);
     if (!N)
index 0a3ae7a1968c6fedc83aea25f32b1a042d35fd07..1e01cdf4ca6ba5c3dece6b032d991b5692d08b67 100644 (file)
@@ -238,6 +238,41 @@ void testPreconditionViolationInInlinedFunction(Dummy *p) {
   doNotWarnWhenPreconditionIsViolated(p);
 }
 
+@interface TestInlinedPreconditionViolationClass : NSObject
+@end
+
+@implementation TestInlinedPreconditionViolationClass
+-(Dummy * _Nonnull) calleeWithParam:(Dummy * _Nonnull) p2 {
+  Dummy *x = 0;
+  if (!p2) // p2 binding becomes dead at this point.
+    return x; // no-warning
+  else
+   return p2;
+}
+
+-(Dummy *)callerWithParam:(Dummy * _Nonnull) p1 {
+  return [self calleeWithParam:p1];
+}
+
+@end
+
+int * _Nonnull InlinedPreconditionViolationInFunctionCallee(int * _Nonnull p2) {
+  int *x = 0;
+  if (!p2) // p2 binding becomes dead at this point.
+    return x; // no-warning
+  else
+   return p2;
+}
+
+int * _Nonnull InlinedReturnNullOverSuppressionCallee(int * _Nonnull p2) {
+  int *result = 0;
+  return result; // no-warning; but this is an over suppression
+}
+
+int *InlinedReturnNullOverSuppressionCaller(int * _Nonnull p1) {
+  return InlinedReturnNullOverSuppressionCallee(p1);
+}
+
 void inlinedNullable(Dummy *_Nullable p) {
   if (p) return;
 }