xref: /llvm-project/clang/test/CodeGen/bounds-checking-fam.c (revision 7f93ae808634e33e4dc9bce753c909aa5f9a6eb4)
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