mirror of https://github.com/microsoft/clang.git
[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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@301482 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e05b249e25
commit
1e2ea9a764
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue