1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
// RUN: %clang_cc1 -std=c++20 -Wno-everything -Wunsafe-buffer-usage \
// RUN: -fsafe-buffer-usage-suggestions \
// RUN: -verify %s
// CHECK-NOT: [-Wunsafe-buffer-usage]
void foo(unsigned idx) {
int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}}
// expected-note@-1{{change type of 'buffer' to 'std::array' to label it for hardening}}
buffer[idx] = 0; // expected-note{{used in buffer access here}}
}
int global_buffer[10]; // expected-warning{{'global_buffer' is an unsafe buffer that does not perform bounds checks}}
void foo2(unsigned idx) {
global_buffer[idx] = 0; // expected-note{{used in buffer access here}}
}
struct Foo {
int member_buffer[10];
int x;
};
void foo2(Foo& f, unsigned idx) {
f.member_buffer[idx] = 0; // expected-warning{{unsafe buffer access}}
}
void constant_idx_safe(unsigned idx) {
int buffer[10];
buffer[9] = 0;
}
void constant_idx_safe0(unsigned idx) {
int buffer[10];
buffer[0] = 0;
}
int array[10]; // expected-warning 3{{'array' is an unsafe buffer that does not perform bounds checks}}
void circular_access_unsigned(unsigned idx) {
array[idx % 10];
array[idx % 11]; // expected-note {{used in buffer access here}}
array[(idx + 3) % 10];
array[(--idx) % 8];
array[idx & 9 % 10];
array[9 & idx % 11];
array [12 % 10];
}
void circular_access_signed(int idx) {
array[idx % 10]; // expected-note {{used in buffer access here}}
}
void masked_idx1(unsigned long long idx, Foo f) {
// Bitwise and operation
array[idx & 5] = 10; // no-warning
array[5 &idx] = 12; // no-warning
array[idx & 11 & 5] = 3; // no warning
array[idx & 11] = 20; // expected-note{{used in buffer access here}}
array[idx &=5]; // expected-note{{used in buffer access here}}
array[f.x & 5]; // no-warning
array[5 & f.x]; // no-warning
array[f.x & (-5)]; // expected-note{{used in buffer access here}}
}
typedef unsigned long long uint64_t;
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
void type_conversions(uint64_t idx1, uint32_t idx2, uint8_t idx3) {
array[(uint32_t)idx1 & 3];
array[idx2 & 3];
array[idx3 & 3];
}
int array2[5]; // expected-warning {{'array2' is an unsafe buffer that does not perform bounds checks}}
void masked_idx_safe(unsigned long long idx) {
array2[6 & 5]; // no warning
array2[6 & idx & (idx + 1) & 5]; // expected-note{{used in buffer access here}}
}
void constant_idx_unsafe(unsigned idx) {
int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}}
// expected-note@-1{{change type of 'buffer' to 'std::array' to label it for hardening}}
buffer[10] = 0; // expected-note{{used in buffer access here}}
}
void constant_id_string(unsigned idx) {
char safe_char = "abc"[1]; // no-warning
safe_char = ""[0];
safe_char = "\0"[0];
char abcd[5] = "abc";
abcd[2]; // no-warning
char unsafe_char = "abc"[3];
unsafe_char = "abc"[-1]; //expected-warning{{unsafe buffer access}}
unsafe_char = ""[1]; //expected-warning{{unsafe buffer access}}
unsafe_char = ""[idx]; //expected-warning{{unsafe buffer access}}
}
typedef float Float4x4[4][4];
// expected-warning@+1 {{'matrix' is an unsafe buffer that does not perform bounds checks}}
float two_dimension_array(Float4x4& matrix, unsigned idx) {
// expected-warning@+1{{unsafe buffer access}}
float a = matrix[0][4];
a = matrix[0][3];
// expected-note@+1{{used in buffer access here}}
a = matrix[4][0];
a = matrix[idx][0]; // expected-note{{used in buffer access here}}
a = matrix[0][idx]; //expected-warning{{unsafe buffer access}}
a = matrix[idx][idx]; //expected-warning{{unsafe buffer access}} // expected-note{{used in buffer access here}}
return matrix[1][1];
}
typedef float Float2x3x4[2][3][4];
float multi_dimension_array(Float2x3x4& matrix) {
float *f = matrix[0][2];
return matrix[1][2][3];
}
char array_strings[][11] = {
"Apple", "Banana", "Cherry", "Date", "Elderberry"
};
char array_string[] = "123456";
char access_strings() {
char c = array_strings[0][4];
c = array_strings[3][10];
c = array_string[5];
return c;
}
struct T {
int array[10];
};
const int index = 1;
constexpr int get_const(int x) {
if(x < 3)
return ++x;
else
return x + 5;
};
void array_indexed_const_expr(unsigned idx) {
// expected-note@+2 {{change type of 'arr' to 'std::array' to label it for hardening}}
// expected-warning@+1{{'arr' is an unsafe buffer that does not perform bounds checks}}
int arr[10];
arr[sizeof(int)] = 5;
int array[sizeof(T)];
array[sizeof(int)] = 5;
array[sizeof(T) -1 ] = 3;
int k = arr[6 & 5];
k = arr[2 << index];
k = arr[8 << index]; // expected-note {{used in buffer access here}}
k = arr[16 >> 1];
k = arr[get_const(index)];
k = arr[get_const(5)]; // expected-note {{used in buffer access here}}
k = arr[get_const(4)];
}
template<unsigned length>
consteval bool isNullTerminated(const char (&literal)[length])
{
return literal[length - 1] == '\0';
}
template <typename T, unsigned M, unsigned N>
T access2DArray(const T (&arr)[M][N]) {
return arr[M-1][N-1];
}
template<unsigned idx>
constexpr int access_elements() {
int arr[idx + 20];
return arr[idx + 1];
}
// Test array accesses where const sized arrays are accessed safely with indices
// that evaluate to a const values and depend on template arguments.
void test_template_methods()
{
constexpr char arr[] = "Good Morning!"; // = {'a', 'b', 'c', 'd', 'e'};
isNullTerminated(arr);
isNullTerminated("");
auto _ = isNullTerminated("hello world\n");
access_elements<5>();
int arr1[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
access2DArray(arr1);
}
|