]> granicus.if.org Git - clang/commitdiff
[ubsan] Relax nullability-return for blocks with deduced types
authorVedant Kumar <vsk@apple.com>
Tue, 26 Jun 2018 02:50:04 +0000 (02:50 +0000)
committerVedant Kumar <vsk@apple.com>
Tue, 26 Jun 2018 02:50:04 +0000 (02:50 +0000)
When the return type of an ObjC-style block literals is deduced, pick
the candidate type with the strictest nullability annotation applicable
to every other candidate.

This suppresses a UBSan false-positive in situations where a too-strict
nullability would be deduced, despite the fact that the returned value
would be implicitly cast to _Nullable.

rdar://41317163

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

include/clang/Basic/Specifiers.h
lib/Sema/SemaLambda.cpp
test/CodeGenObjC/ubsan-nullability.m

index 6fb96f67bbf71532c28ce8e199523afc828c4500..c5edb5ea968c24f9060812285ad7b9f2421508c0 100644 (file)
@@ -294,6 +294,12 @@ namespace clang {
     Unspecified
   };
 
+  /// Return true if \p L has a weaker nullability annotation than \p R. The
+  /// ordering is: Unspecified < Nullable < NonNull.
+  inline bool operator<(NullabilityKind L, NullabilityKind R) {
+    return uint8_t(L) > uint8_t(R);
+  }
+
   /// Retrieve the spelling of the given nullability kind.
   llvm::StringRef getNullabilitySpelling(NullabilityKind kind,
                                          bool isContextSensitive = false);
index b6ea484cea65d358fca29b7ea56eb1de147dca1b..98b428b08999a8fd19181a7f1c57f6cd1a6a3f4e 100644 (file)
@@ -707,8 +707,15 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
     QualType ReturnType =
         (RetE ? RetE->getType() : Context.VoidTy).getUnqualifiedType();
     if (Context.getCanonicalFunctionResultType(ReturnType) ==
-          Context.getCanonicalFunctionResultType(CSI.ReturnType))
+          Context.getCanonicalFunctionResultType(CSI.ReturnType)) {
+      // Use the return type with the strictest possible nullability annotation.
+      auto RetTyNullability = ReturnType->getNullability(Ctx);
+      auto BlockNullability = CSI.ReturnType->getNullability(Ctx);
+      if (BlockNullability &&
+          (!RetTyNullability || *RetTyNullability < *BlockNullability))
+        CSI.ReturnType = ReturnType;
       continue;
+    }
 
     // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
     // TODO: It's possible that the *first* return is the divergent one.
index eeb24b03c868eb8ffdc354d8c68f066a4736cc8b..8e7a9cba7c71c8cfc2851ef3130f44d88e295890 100644 (file)
@@ -1,6 +1,6 @@
 // REQUIRES: asserts
-// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s
-// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s
+// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fblocks -fobjc-arc -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fblocks -fobjc-arc -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s
 
 // CHECK: [[NONNULL_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 100, i32 6
 // CHECK: [[NONNULL_ARG_LOC:@.*]] = private unnamed_addr global {{.*}} i32 204, i32 15 {{.*}} i32 190, i32 23
@@ -177,6 +177,37 @@ void call_A(A *a, int *p) {
 
 void dont_crash(int *_Nonnull p, ...) {}
 
+@protocol NSObject
+- (id)init;
+@end
+@interface NSObject <NSObject> {}
+@end
+
+#pragma clang assume_nonnull begin
+
+/// Create a "NSObject * _Nonnull" instance.
+NSObject *get_nonnull_error() {
+  // Use nil for convenience. The actual object doesn't matter.
+  return (NSObject *)NULL;
+}
+
+NSObject *_Nullable no_null_return_value_diagnostic(int flag) {
+// CHECK-LABEL: define internal {{.*}}no_null_return_value_diagnostic{{i?}}_block_invoke
+// CHECK-NOT: @__ubsan_handle_nullability_return
+  NSObject *_Nullable (^foo)() = ^() {
+    if (flag) {
+      // Clang should not infer a nonnull return value for this block when this
+      // call is present.
+      return get_nonnull_error();
+    } else {
+      return (NSObject *)NULL;
+    }
+  };
+  return foo();
+}
+
+#pragma clang assume_nonnull end
+
 int main() {
   nonnull_retval1(INULL);
   nonnull_retval2(INNULL, INNULL, INULL, (int *_Nullable)NULL, 0, 0, 0, 0);
@@ -188,5 +219,7 @@ int main() {
   nonnull_init2(INULL);
   call_A((A *)NULL, INULL);
   dont_crash(INNULL, NULL);
+  no_null_return_value_diagnostic(0);
+  no_null_return_value_diagnostic(1);
   return 0;
 }