1 // REQUIRES: x86-registered-target
2 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=0 -fsanitize=array-bounds %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0
3 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=0 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0,CXX,CXX-STRICT-0
4 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=1 -fsanitize=array-bounds %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1
5 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=1 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1,CXX
6 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2
7 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2,CXX
8 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3
9 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3,CXX
10 // Before flexible array member was added to C99, many projects use a
11 // one-element array as the last member of a structure as an alternative.
12 // E.g. https://github.com/python/cpython/issues/84301
13 // Suppress such errors with -fstrict-flex-arrays=0.
14
15 struct Incomplete {
16 int ignored;
17 int a[];
18 };
19 struct Zero {
20 int ignored;
21 int a[0];
22 };
23 struct One {
24 int ignored;
25 int a[1];
26 };
27 struct Two {
28 int ignored;
29 int a[2];
30 };
31 struct Three {
32 int ignored;
33 int a[3];
34 };
35
36 // CHECK-LABEL: define {{.*}} @{{.*}}test_incomplete{{.*}}(
test_incomplete(struct Incomplete * p,int i)37 int test_incomplete(struct Incomplete *p, int i) {
38 // CHECK-STRICT-0-NOT: @__ubsan
39 // CHECK-STRICT-1-NOT: @__ubsan
40 // CHECK-STRICT-2-NOT: @__ubsan
41 // CHECK-STRICT-3-NOT: @__ubsan
42 return p->a[i] + (p->a)[i];
43 }
44
45 // CHECK-LABEL: define {{.*}} @{{.*}}test_zero{{.*}}(
test_zero(struct Zero * p,int i)46 int test_zero(struct Zero *p, int i) {
47 // CHECK-STRICT-0-NOT: @__ubsan
48 // CHECK-STRICT-1-NOT: @__ubsan
49 // CHECK-STRICT-2-NOT: @__ubsan
50 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
51 return p->a[i] + (p->a)[i];
52 }
53
54 // CHECK-LABEL: define {{.*}} @{{.*}}test_one{{.*}}(
test_one(struct One * p,int i)55 int test_one(struct One *p, int i) {
56 // CHECK-STRICT-0-NOT: @__ubsan
57 // CHECK-STRICT-1-NOT: @__ubsan
58 // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
59 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
60 return p->a[i] + (p->a)[i];
61 }
62
63 // CHECK-LABEL: define {{.*}} @{{.*}}test_two{{.*}}(
test_two(struct Two * p,int i)64 int test_two(struct Two *p, int i) {
65 // CHECK-STRICT-0-NOT: @__ubsan
66 // CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort(
67 // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
68 return p->a[i] + (p->a)[i];
69 }
70
71 // CHECK-LABEL: define {{.*}} @{{.*}}test_three{{.*}}(
test_three(struct Three * p,int i)72 int test_three(struct Three *p, int i) {
73 // CHECK-STRICT-0-NOT: @__ubsan
74 // CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort(
75 // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
76 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
77 return p->a[i] + (p->a)[i];
78 }
79
80 union uZero {
81 int a[0];
82 };
83 union uOne {
84 int a[1];
85 };
86 union uTwo {
87 int a[2];
88 };
89 union uThree {
90 int a[3];
91 };
92
93 // CHECK-LABEL: define {{.*}} @{{.*}}test_uzero{{.*}}(
test_uzero(union uZero * p,int i)94 int test_uzero(union uZero *p, int i) {
95 // CHECK-STRICT-0-NOT: @__ubsan
96 // CHECK-STRICT-1-NOT: @__ubsan
97 // CHECK-STRICT-2-NOT: @__ubsan
98 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
99 return p->a[i] + (p->a)[i];
100 }
101
102 // CHECK-LABEL: define {{.*}} @{{.*}}test_uone{{.*}}(
test_uone(union uOne * p,int i)103 int test_uone(union uOne *p, int i) {
104 // CHECK-STRICT-0-NOT: @__ubsan
105 // CHECK-STRICT-1-NOT: @__ubsan
106 // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
107 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
108 return p->a[i] + (p->a)[i];
109 }
110
111 // CHECK-LABEL: define {{.*}} @{{.*}}test_utwo{{.*}}(
test_utwo(union uTwo * p,int i)112 int test_utwo(union uTwo *p, int i) {
113 // CHECK-STRICT-0-NOT: @__ubsan
114 // CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort(
115 // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
116 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
117 return p->a[i] + (p->a)[i];
118 }
119
120 // CHECK-LABEL: define {{.*}} @{{.*}}test_uthree{{.*}}(
test_uthree(union uThree * p,int i)121 int test_uthree(union uThree *p, int i) {
122 // CHECK-STRICT-0-NOT: @__ubsan
123 // CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort(
124 // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
125 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
126 return p->a[i] + (p->a)[i];
127 }
128
129 #define FLEXIBLE 1
130 struct Macro {
131 int a[FLEXIBLE];
132 };
133
134 // CHECK-LABEL: define {{.*}} @{{.*}}test_macro{{.*}}(
test_macro(struct Macro * p,int i)135 int test_macro(struct Macro *p, int i) {
136 // CHECK-STRICT-0-NOT: @__ubsan
137 // CHECK-STRICT-1-NOT: @__ubsan
138 // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
139 // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
140 return p->a[i] + (p->a)[i];
141 }
142
143 #if defined __cplusplus
144
145 struct Base {
146 int b;
147 };
148 struct NoStandardLayout : Base {
149 int a[1];
150 };
151
152 // CXX-LABEL: define {{.*}} @{{.*}}test_nostandardlayout{{.*}}(
test_nostandardlayout(NoStandardLayout * p,int i)153 int test_nostandardlayout(NoStandardLayout *p, int i) {
154 // CXX-STRICT-0-NOT: @__ubsan
155 return p->a[i] + (p->a)[i];
156 }
157
158 template<int N> struct Template {
159 int a[N];
160 };
161
162 // CXX-LABEL: define {{.*}} @{{.*}}test_template{{.*}}(
test_template(Template<1> * p,int i)163 int test_template(Template<1> *p, int i) {
164 // CXX-STRICT-0-NOT: @__ubsan
165 return p->a[i] + (p->a)[i];
166 }
167
168 #endif
169