From 6b22dda5a3909f46862ec001110b5d4671bbf142 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 26 Apr 2017 21:55:17 +0000 Subject: [PATCH] [ubsan] nullability-assign: Check assignments into C++ structs Fix the nullability-assign check so that it can handle assignments into C++ structs. Previously, such assignments were not instrumented. Testing: check-clang, check-ubsan, enabling the existing test in ObjC++ mode, and building some Apple frameworks with -fsanitize=nullability. llvm-svn: 301482 --- clang/lib/CodeGen/CGExpr.cpp | 2 + clang/test/CodeGenCXX/ubsan-nullability-assign.cpp | 35 +++++++++++++++++ clang/test/CodeGenObjC/ubsan-nullability.m | 44 ++++++++++++---------- 3 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 clang/test/CodeGenCXX/ubsan-nullability-assign.cpp diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index d0aacf6..863b438 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4065,6 +4065,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { RValue RV = EmitAnyExpr(E->getRHS()); LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); + if (RV.isScalar()) + EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); EmitStoreThroughLValue(RV, LV); return LV; } diff --git a/clang/test/CodeGenCXX/ubsan-nullability-assign.cpp b/clang/test/CodeGenCXX/ubsan-nullability-assign.cpp new file mode 100644 index 0000000..3f85c88 --- /dev/null +++ b/clang/test/CodeGenCXX/ubsan-nullability-assign.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -x c++ -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=nullability-assign | FileCheck %s + +struct S1 { + int *_Nonnull p; +}; + +struct S2 { + S1 s1; +}; + +union U1 { + S1 s1; + S2 s2; +}; + +// CHECK-LABEL: define void @{{.*}}f1 +void f1(int *p) { + U1 u; + + // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize + // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize + // CHECK: call void @__ubsan_handle_type_mismatch{{.*}} !nosanitize + // CHECK: store + u.s1.p = p; + + // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize + // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize + // CHECK: call void @__ubsan_handle_type_mismatch{{.*}} !nosanitize + // CHECK: store + u.s2.s1.p = p; + + // CHECK-NOT: __ubsan_handle_type_mismatch + // CHECK-NOT: store + // CHECK: ret void +} diff --git a/clang/test/CodeGenObjC/ubsan-nullability.m b/clang/test/CodeGenObjC/ubsan-nullability.m index 457f071..7f53ea62 100644 --- a/clang/test/CodeGenObjC/ubsan-nullability.m +++ b/clang/test/CodeGenObjC/ubsan-nullability.m @@ -1,19 +1,22 @@ // 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 // CHECK: [[NONNULL_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 109, i32 1 {{.*}} 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 505, 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 817, i32 1 {{.*}} i32 800, i32 6 #define NULL ((void *)0) +#define INULL ((int *)NULL) +#define INNULL ((int *_Nonnull)NULL) -// CHECK-LABEL: define i32* @nonnull_retval1 +// CHECK-LABEL: define i32* @{{.*}}nonnull_retval1 #line 100 int *_Nonnull nonnull_retval1(int *p) { // CHECK: br i1 true, label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize @@ -29,7 +32,7 @@ int *_Nonnull nonnull_retval1(int *p) { #line 190 void nonnull_arg(int *_Nonnull p) {} -// CHECK-LABEL: define void @call_func_with_nonnull_arg +// CHECK-LABEL: define void @{{.*}}call_func_with_nonnull_arg #line 200 void call_func_with_nonnull_arg(int *_Nonnull p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize @@ -38,7 +41,7 @@ void call_func_with_nonnull_arg(int *_Nonnull p) { nonnull_arg(p); } -// CHECK-LABEL: define void @nonnull_assign1 +// CHECK-LABEL: define void @{{.*}}nonnull_assign1 #line 300 void nonnull_assign1(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize @@ -48,7 +51,7 @@ void nonnull_assign1(int *p) { local = p; } -// CHECK-LABEL: define void @nonnull_assign2 +// CHECK-LABEL: define void @{{.*}}nonnull_assign2 #line 400 void nonnull_assign2(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize @@ -62,17 +65,18 @@ struct S1 { int *_Nonnull mptr; }; -// CHECK-LABEL: define void @nonnull_assign3 +// CHECK-LABEL: define void @{{.*}}nonnull_assign3 #line 500 void nonnull_assign3(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, 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 +// CHECK-LABEL: define void @{{.*}}nonnull_init1 #line 600 void nonnull_init1(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize @@ -81,7 +85,7 @@ void nonnull_init1(int *p) { int *_Nonnull local = p; } -// CHECK-LABEL: define void @nonnull_init2 +// CHECK-LABEL: define void @{{.*}}nonnull_init2 #line 700 void nonnull_init2(int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize @@ -93,7 +97,7 @@ void nonnull_init2(int *p) { int *_Nonnull arr[] = {p, p}; } -// CHECK-LABEL: define i32* @nonnull_retval2 +// CHECK-LABEL: define i32* @{{.*}}nonnull_retval2 #line 800 int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this. int *_Nonnull arg2, //< Test this. @@ -150,7 +154,7 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this. } @end -// CHECK-LABEL: define void @call_A +// CHECK-LABEL: define void @{{.*}}call_A void call_A(A *a, int *p) { // CHECK: [[ICMP:%.*]] = icmp ne i32* [[P1:%.*]], null, !nosanitize // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize @@ -168,15 +172,15 @@ void call_A(A *a, int *p) { void dont_crash(int *_Nonnull p, ...) {} int main() { - nonnull_retval1(NULL); - nonnull_retval2(NULL, NULL, NULL, NULL, 0, 0, 0, 0); - call_func_with_nonnull_arg(NULL); - nonnull_assign1(NULL); - nonnull_assign2(NULL); - nonnull_assign3(NULL); - nonnull_init1(NULL); - nonnull_init2(NULL); - call_A(NULL, NULL); - dont_crash(NULL, NULL); + 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); return 0; } -- 2.7.4