// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ // RUN: -fsafe-buffer-usage-suggestions \ // RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s typedef int * Int_ptr_t; typedef int Int_t; void local_array_subscript_simple() { int tmp; int *p = new int[10]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span p" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}" const int *q = new int[10]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::span q" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:29}:", 10}" tmp = p[5]; tmp = q[5]; // We do not fix the following declaration. Because if the // definition of `Int_ptr_t` gets changed, the fixed code becomes // incorrect and may NOT be noticed. // FIXME: Fix with std::span>? Int_ptr_t x = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] Int_t * z = new int[10]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span z" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}" Int_t * w = new Int_t[10]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span w" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}" tmp = x[5]; tmp = z[5]; tmp = w[5]; } void local_array_subscript_auto() { int tmp; // We do not fix the following declaration because // that'd cause us to hardcode the element type. // FIXME: Can we use the C++17 class template argument deduction // to avoid spelling out the element type? auto p = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] tmp = p[5]; } void local_variable_qualifiers_specifiers() { int a[10]; const int * p = a; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span p" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", 10}" const int * const q = a; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:24}:"std::span const q" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:25-[[@LINE-2]]:25}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}" int tmp; tmp = p[5]; tmp = q[5]; } void local_array_subscript_variable_extent() { int n = 10; int tmp; int *p = new int[n]; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span p" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", n}" // If the extent expression does not have a constant value, we cannot fill the extent for users... int *q = new int[n++]; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span q" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}" tmp = p[5]; tmp = q[5]; } void local_ptr_to_array() { int tmp; int n = 10; int a[10]; int b[n]; // If the extent expression does not have a constant value, we cannot fill the extent for users... int *p = a; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span p" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", 10}" int *q = b; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span q" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}" // No way to know if `n` is ever mutated since `int b[n];`, so no way to figure out the extent tmp = p[5]; tmp = q[5]; } void local_ptr_addrof_init() { int var; int * q = &var; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span q" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:", 1}" // This expression involves unsafe buffer accesses, which will crash // at runtime after applying the fix-it, var = q[5]; } void decl_without_init() { int tmp; int * p; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span p" // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}} Int_t * q; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span q" // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}} tmp = p[5]; tmp = q[5]; } // Explicit casts are required in the following cases. No way to // figure out span extent for them automatically. void explict_cast() { int tmp; int * p = (int*) new int[10][10]; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:35-[[@LINE-3]]:35}:", <# placeholder #>}" tmp = p[5]; int a; char * q = (char *)&a; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:13}:"std::span q" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}" tmp = (int) q[5]; void * r = &a; char * s = (char *) r; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:13}:"std::span s" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}" tmp = (int) s[5]; } void null_init() { #define NULL 0 int tmp; int * my_null = 0; int * p = 0; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p" // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}} int * g = NULL; // cannot handle fix-its involving macros for now // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: int * f = nullptr; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span f" // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}} // In case of value dependencies, we give up int * q = my_null; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span q" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", <# placeholder #>}" int * r = my_null + 0; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span r" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", <# placeholder #>}" tmp = p[5]; // `p[5]` will cause crash after `p` being transformed to be a `std::span` tmp = q[5]; // Similar for the rests. tmp = r[5]; tmp = g[5]; tmp = f[5]; #undef NULL } void unsupported_multi_decl(int * x) { int * p = x, * q = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] *p = q[5]; } void macroVariableIdentifier() { #define MY_NAME p #define MY_NAME_ARG(x) q // Although fix-its include macros, the macros do not overlap with // the bounds of the source range of these fix-its. So these fix-its // are valid. int * MY_NAME = new int[10]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span MY_NAME" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:30-[[@LINE-3]]:30}:", 10}" int * MY_NAME_ARG( 'x' ) = new int[10]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:29}:"std::span MY_NAME_ARG( 'x' )" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:41-[[@LINE-3]]:41}:", 10}" p[5] = 5; q[5] = 5; #undef MY_NAME #undef MY_NAME_ARG } void unsupported_fixit_overlapping_macro(int * x) { int tmp; // In the case below, a tentative fix-it replaces `MY_INT * p =` with `std::span p `. // The bounds of the source range of the fix-it overlap with the use of the macro // `MY_INT`. The fix-it is discarded then. // FIXME: we do not have to discard a fix-it if its begin location // overlaps with the begin location of a macro. Similar for end // locations. #define MY_INT int MY_INT * p = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] tmp = p[5]; #define MY_VAR(name) int * name MY_VAR(q) = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] tmp = q[5]; // In cases where fix-its do not change the original code where // macros are used, those fix-its will be emitted. For example, // fixits are inserted before and after `new MY_INT[MY_TEN]` below. #define MY_TEN 10 int * g = new MY_INT[MY_TEN]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span g" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:31-[[@LINE-3]]:31}:", MY_TEN}" tmp = g[5]; #undef MY_INT #undef MY_VAR #undef MY_TEN } void unsupported_subscript_negative(int i, unsigned j, unsigned long k) { int tmp; int * p = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] tmp = p[-1]; // If `p` is made a span, this `[]` operation is wrong, // so no fix-it emitted. int * q = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] tmp = q[5]; tmp = q[i]; // If `q` is made a span, this `[]` operation may be // wrong as we do not know if `i` is non-negative, so // no fix-it emitted. int * r = new int[10]; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span r" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" tmp = r[j] + r[k]; // both `j` and `k` are unsigned so they must be non-negative tmp = r[(unsigned int)-1]; // a cast-to-unsigned-expression is also non-negative } #define DEFINE_PTR(X) int* ptr = (X); void all_vars_in_macro() { int* local; DEFINE_PTR(local) ptr[1] = 0; } void few_vars_in_macro() { int* local; DEFINE_PTR(local) ptr[1] = 0; int tmp; ptr[2] = 30; int * p = new int[10]; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" tmp = p[5]; int val = *p; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:"" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"[0]" val = *p + 30; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:10}:"" // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:11}:"[0]" }