llvm/clang/test/CodeGenObjC/ubsan-nullability.m

// REQUIRES: asserts
// RUN: %clang_cc1 -no-enable-noundef-analysis -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 -no-enable-noundef-analysis -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
// CHECK: [[NONNULL_ASSIGN1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 305, i32 9
// CHECK: [[NONNULL_ASSIGN2_LOC:@.*]] = private unnamed_addr global {{.*}} i32 405, i32 10
// CHECK: [[NONNULL_ASSIGN3_LOC:@.*]] = private unnamed_addr global {{.*}} i32 506, i32 10
// CHECK: [[NONNULL_INIT1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 604, i32 25
// CHECK: [[NONNULL_INIT2_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 26
// CHECK: [[NONNULL_INIT2_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 29
// CHECK: [[NONNULL_RV_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 800, i32 6

#define NULL ((void *)0)
#define INULL ((int *)NULL)
#define INNULL ((int *_Nonnull)NULL)

// CHECK-LABEL: define{{.*}} ptr @{{.*}}nonnull_retval1
#line 100
int *_Nonnull nonnull_retval1(int *p) {
  // CHECK: nullcheck:
  // CHECK: [[ICMP:%.*]] = icmp ne ptr {{.*}}, null, !nosanitize
  // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC1]]
  return p;
  // CHECK: ret ptr
}

#line 190
void nonnull_arg(int *_Nonnull p) {}

// CHECK-LABEL: define{{.*}} void @{{.*}}call_func_with_nonnull_arg
#line 200
void call_func_with_nonnull_arg(int *_Nonnull p) {
  // CHECK: [[ICMP:%.*]] = icmp ne ptr {{.*}}, null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_nullability_arg{{.*}}[[NONNULL_ARG_LOC]]
  nonnull_arg(p);
}

// CHECK-LABEL: define{{.*}} void @{{.*}}nonnull_assign1
#line 300
void nonnull_assign1(int *p) {
  // CHECK: [[ICMP:%.*]] = icmp ne ptr {{.*}}, null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_ASSIGN1_LOC]]
  int *_Nonnull local;
  local = p;
}

// CHECK-LABEL: define{{.*}} void @{{.*}}nonnull_assign2
#line 400
void nonnull_assign2(int *p) {
  // CHECK: [[ICMP:%.*]] = icmp ne ptr %{{.*}}, null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_ASSIGN2_LOC]]
  int *_Nonnull arr[1];
  arr[0] = p;
}

struct S1 {
  int *_Nonnull mptr;
};

// CHECK-LABEL: define{{.*}} void @{{.*}}nonnull_assign3
#line 500
void nonnull_assign3(int *p) {
  // CHECK: [[ICMP:%.*]] = icmp ne ptr %{{.*}}, null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_ASSIGN3_LOC]]
  // CHECK-NOT: call void @__ubsan_handle_type_mismatch
  struct S1 s;
  s.mptr = p;
}

// CHECK-LABEL: define{{.*}} void @{{.*}}nonnull_init1
#line 600
void nonnull_init1(int *p) {
  // CHECK: [[ICMP:%.*]] = icmp ne ptr %{{.*}}, null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_INIT1_LOC]]
  int *_Nonnull local = p;
}

// CHECK-LABEL: define{{.*}} void @{{.*}}nonnull_init2
#line 700
void nonnull_init2(int *p) {
  // CHECK: [[ICMP:%.*]] = icmp ne ptr %{{.*}}, null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_INIT2_LOC1]]
  // CHECK: [[ICMP:%.*]] = icmp ne ptr %{{.*}}, null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_type_mismatch{{.*}}[[NONNULL_INIT2_LOC2]]
  int *_Nonnull arr[] = {p, p};
}

// CHECK-LABEL: define{{.*}} ptr @{{.*}}nonnull_retval2
#line 800
int *_Nonnull nonnull_retval2(int *_Nonnull arg1,  //< Test this.
                              int *_Nonnull arg2,  //< Test this.
                              int *_Nullable arg3, //< Don't test the rest.
                              int *arg4,
                              int arg5, ...) {
  // CHECK: [[ARG1CMP:%.*]] = icmp ne ptr %arg1, null, !nosanitize
  // CHECK-NEXT: [[DO_RV_CHECK_1:%.*]] = and i1 true, [[ARG1CMP]], !nosanitize
  // CHECK: [[ARG2CMP:%.*]] = icmp ne ptr %arg2, null, !nosanitize
  // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[DO_RV_CHECK_1]], [[ARG2CMP]]
  // CHECK: [[SLOC_PTR:%.*]] = load ptr, ptr %return.sloc.ptr
  // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne ptr [[SLOC_PTR]], null
  // CHECK-NEXT: [[DO_RV_CHECK_3:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK_2]]
  // CHECK: br i1 [[DO_RV_CHECK_3]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
  // CHECK: [[NULL]]:
  // CHECK-NEXT: [[ICMP:%.*]] = icmp ne ptr {{.*}}, null, !nosanitize
  // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC2]]
  return arg1;
  // CHECK: [[NONULL]]:
  // CHECK-NEXT: ret ptr
}

@interface A
+(int *_Nonnull) objc_clsmethod: (int *_Nonnull) arg1;
-(int *_Nonnull) objc_method: (int *_Nonnull) arg1;
@end

@implementation A

// CHECK-LABEL: define internal ptr @"\01+[A objc_clsmethod:]"
+(int *_Nonnull) objc_clsmethod: (int *_Nonnull) arg1 {
  // CHECK: [[ARG1CMP:%.*]] = icmp ne ptr %arg1, null, !nosanitize
  // CHECK-NEXT: [[DO_RV_CHECK:%.*]] = and i1 true, [[ARG1CMP]]
  // CHECK: [[SLOC_PTR:%.*]] = load ptr, ptr %return.sloc.ptr
  // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne ptr [[SLOC_PTR]], null
  // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK]]
  // CHECK: br i1 [[DO_RV_CHECK_2]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
  // CHECK: [[NULL]]:
  // CHECK-NEXT: [[ICMP:%.*]] = icmp ne ptr {{.*}}, null, !nosanitize
  // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_nullability_return{{.*}}
  return arg1;
  // CHECK: [[NONULL]]:
  // CHECK-NEXT: ret ptr
}

// CHECK-LABEL: define internal ptr @"\01-[A objc_method:]"
-(int *_Nonnull) objc_method: (int *_Nonnull) arg1 {
  // CHECK: [[ARG1CMP:%.*]] = icmp ne ptr %arg1, null, !nosanitize
  // CHECK-NEXT: [[DO_RV_CHECK:%.*]] = and i1 true, [[ARG1CMP]]
  // CHECK: [[SLOC_PTR:%.*]] = load ptr, ptr %return.sloc.ptr
  // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne ptr [[SLOC_PTR]], null
  // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK]]
  // CHECK: br i1 [[DO_RV_CHECK_2]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
  // CHECK: [[NULL]]:
  // CHECK-NEXT: [[ICMP:%.*]] = icmp ne ptr {{.*}}, null, !nosanitize
  // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_nullability_return{{.*}}
  return arg1;
  // CHECK: [[NONULL]]:
  // CHECK-NEXT: ret ptr
}
@end

// CHECK-LABEL: define{{.*}} void @{{.*}}call_A
void call_A(A *a, int *p) {
  // CHECK: [[ICMP:%.*]] = icmp ne ptr [[P1:%.*]], null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_nullability_arg{{.*}} !nosanitize
  // CHECK: call ptr @objc_msgSend({{.*}}, ptr [[P1]])
  [a objc_method: p];

  // CHECK: [[ICMP:%.*]] = icmp ne ptr [[P2:%.*]], null, !nosanitize
  // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
  // CHECK: call void @__ubsan_handle_nullability_arg{{.*}} !nosanitize
  // CHECK: call ptr @objc_msgSend({{.*}}, ptr [[P2]])
  [A objc_clsmethod: 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(void) {
  // 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)(void) = ^(void) {
    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(void) {
  nonnull_retval1(INULL);
  nonnull_retval2(INNULL, INNULL, INULL, (int *_Nullable)NULL, 0, 0, 0, 0);
  call_func_with_nonnull_arg(INNULL);
  nonnull_assign1(INULL);
  nonnull_assign2(INULL);
  nonnull_assign3(INULL);
  nonnull_init1(INULL);
  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;
}