mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 09:26:41 +00:00

Do not warn when a constant sized array is indexed with an expression that contains bitwise and operation involving constants and it always results in a bound safe access. (rdar://136684050) --------- Co-authored-by: MalavikaSamak <malavika2@apple.com>
195 lines
5.4 KiB
C++
195 lines
5.4 KiB
C++
// 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 {{'array' is an unsafe buffer that does not perform bounds checks}}
|
|
|
|
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);
|
|
}
|