316 lines · cpp
1// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \2// RUN: -fsafe-buffer-usage-suggestions \3// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s4typedef int * Int_ptr_t;5typedef int Int_t;6 7void local_array_subscript_simple() {8 int tmp;9 int *p = new int[10];10 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "11 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"12 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"13 const int *q = new int[10];14 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const> "15 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:"{"16 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:29}:", 10}"17 tmp = p[5];18 tmp = q[5];19 20 // We do not fix the following declaration. Because if the21 // definition of `Int_ptr_t` gets changed, the fixed code becomes22 // incorrect and may NOT be noticed.23 // FIXME: Fix with std::span<std::remove_pointer_t<Int_ptr_t>>?24 Int_ptr_t x = new int[10];25 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]26 Int_t * z = new int[10];27 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span<Int_t>"28 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"29 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}"30 Int_t * w = new Int_t[10];31 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span<Int_t>"32 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"33 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}"34 35 tmp = x[5];36 tmp = z[5];37 tmp = w[5];38}39 40void local_array_subscript_auto() {41 int tmp;42 // We do not fix the following declaration because43 // that'd cause us to hardcode the element type.44 // FIXME: Can we use the C++17 class template argument deduction45 // to avoid spelling out the element type?46 auto p = new int[10];47 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]48 tmp = p[5];49}50 51void local_variable_qualifiers_specifiers() {52 int a[10];53 const int * p = a;54 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const>"55 const int * const q = a;56 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const>"57 int tmp;58 tmp = p[5];59 tmp = q[5];60 61 [[deprecated]] const int * x = a;62 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:18-[[@LINE-1]]:29}:"std::span<int const>"63 const int * y [[deprecated]];64 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const>"65 tmp = x[5];66 tmp = y[5];67}68 69void local_variable_unsupported_specifiers() {70 int a[10];71 const int * p [[deprecated]] = a; // not supported because the attribute overlaps the source range of the declaration72 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:73 74 static const int * q = a; // storage specifier not supported yet75 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:76 77 extern int * x; // storage specifier not supported yet78 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:79 80 constexpr int * y = 0; // `constexpr` specifier not supported yet81 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:82 83 int tmp;84 85 tmp = p[5];86 tmp = q[5];87 tmp = x[5];88 tmp = y[5];89}90 91void local_array_subscript_variable_extent() {92 int n = 10;93 int tmp;94 int *p = new int[n];95 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "96 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"97 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", n}"98 // If the extent expression does not have a constant value, we cannot fill the extent for users...99 int *q = new int[n++];100 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "101 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"102 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"103 tmp = p[5];104 tmp = q[5];105}106 107 108void local_ptr_to_array() {109 int tmp;110 int n = 10;111 int a[10];112 int b[n]; // If the extent expression does not have a constant value, we cannot fill the extent for users...113 int *p = a;114 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "115 int *q = b;116 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "117 // No way to know if `n` is ever mutated since `int b[n];`, so no way to figure out the extent118 tmp = p[5];119 tmp = q[5];120}121 122void local_ptr_addrof_init() {123 int var;124 int * q = &var;125 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"126 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"127 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:", 1}"128 // This expression involves unsafe buffer accesses, which will crash129 // at runtime after applying the fix-it,130 var = q[5];131}132 133void decl_without_init() {134 int tmp;135 int * p;136 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"137 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}138 Int_t * q;139 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span<Int_t>"140 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}141 tmp = p[5];142 tmp = q[5];143}144 145// Explicit casts are required in the following cases. No way to146// figure out span extent for them automatically.147void explict_cast() {148 int tmp;149 int * p = (int*) new int[10][10];150 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"151 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"152 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:35-[[@LINE-3]]:35}:", <# placeholder #>}"153 tmp = p[5];154 155 int a;156 char * q = (char *)&a;157 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span<char>"158 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{"159 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"160 tmp = (int) q[5];161 162 void * r = &a;163 char * s = (char *) r;164 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span<char>"165 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{"166 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"167 tmp = (int) s[5];168}169 170void null_init() {171#define NULL 0172 int tmp;173 int * my_null = 0;174 int * p = 0;175 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"176 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}177 int * g = NULL; // cannot handle fix-its involving macros for now178 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:179 int * f = nullptr;180 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"181 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}182 183 // In case of value dependencies, we give up184 int * q = my_null;185 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"186 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"187 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", <# placeholder #>}"188 int * r = my_null + 0;189 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"190 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"191 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}"192 193 tmp = p[5]; // `p[5]` will cause crash after `p` being transformed to be a `std::span`194 tmp = q[5]; // Similar for the rests.195 tmp = r[5];196 tmp = g[5];197 tmp = f[5];198#undef NULL199}200 201 202void unsupported_multi_decl(int * x) {203 int * p = x, * q = new int[10];204 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]205 *p = q[5];206}207 208void macroVariableIdentifier() {209#define MY_NAME p210#define MY_NAME_ARG(x) q211 212 // Although fix-its include macros, the macros do not overlap with213 // the bounds of the source range of these fix-its. So these fix-its214 // are valid.215 216 int * MY_NAME = new int[10];217 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"218 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{"219 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:30-[[@LINE-3]]:30}:", 10}"220 int * MY_NAME_ARG( 'x' ) = new int[10];221 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"222 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:"{"223 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:41-[[@LINE-3]]:41}:", 10}"224 p[5] = 5;225 q[5] = 5;226#undef MY_NAME227#undef MY_NAME_ARG228}229 230void unsupported_fixit_overlapping_macro(int * x) {231 int tmp;232 // In the case below, a tentative fix-it replaces `MY_INT * p =` with `std::span<MY_INT> p `.233 // The bounds of the source range of the fix-it overlap with the use of the macro234 // `MY_INT`. The fix-it is discarded then.235 236 // FIXME: we do not have to discard a fix-it if its begin location237 // overlaps with the begin location of a macro. Similar for end238 // locations.239 240#define MY_INT int241 MY_INT * p = new int[10];242 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]243 tmp = p[5];244 245#define MY_VAR(name) int * name246 MY_VAR(q) = new int[10];247 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]248 tmp = q[5];249 250 // In cases where fix-its do not change the original code where251 // macros are used, those fix-its will be emitted. For example,252 // fixits are inserted before and after `new MY_INT[MY_TEN]` below.253#define MY_TEN 10254 int * g = new MY_INT[MY_TEN];255 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"256 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"257 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:31-[[@LINE-3]]:31}:", MY_TEN}"258 tmp = g[5];259 260#undef MY_INT261#undef MY_VAR262#undef MY_TEN263}264 265void unsupported_subscript_negative(int i, unsigned j, unsigned long k) {266 int tmp;267 int * p = new int[10];268 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]269 270 tmp = p[-1]; // If `p` is made a span, this `[]` operation is wrong,271 // so no fix-it emitted.272 273 int * q = new int[10];274 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]275 276 tmp = q[5];277 tmp = q[i]; // If `q` is made a span, this `[]` operation may be278 // wrong as we do not know if `i` is non-negative, so279 // no fix-it emitted.280 281 int * r = new int[10];282 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"283 // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"284 // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"285 286 tmp = r[j] + r[k]; // both `j` and `k` are unsigned so they must be non-negative287 tmp = r[(unsigned int)-1]; // a cast-to-unsigned-expression is also non-negative288}289 290#define DEFINE_PTR(X) int* ptr = (X);291 292void all_vars_in_macro() {293 int* local;294 DEFINE_PTR(local)295 ptr[1] = 0;296}297 298void few_vars_in_macro() {299 int* local;300 DEFINE_PTR(local)301 ptr[1] = 0;302 int tmp;303 ptr[2] = 30;304 int * p = new int[10];305 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"306 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"307 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"308 tmp = p[5];309 int val = *p;310 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:""311 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"[0]"312 val = *p + 30;313 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:""314 // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:11}:"[0]"315}316