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