mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 00:16:39 +00:00

Do not warn about unsafe buffer access, when multi-dimensional constant arrays are accessed and their indices are within the bounds of the buffer. Warning in such cases would be a false positive. Such a suppression already exists for 1-d arrays and it is now extended to multi-dimensional arrays. (rdar://137926311) (rdar://140320139) Co-authored-by: MalavikaSamak <malavika2@apple.com>
152 lines
5.8 KiB
C++
152 lines
5.8 KiB
C++
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -fcxx-exceptions -fsafe-buffer-usage-suggestions -verify %s
|
|
// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fcxx-exceptions -fdiagnostics-parseable-fixits -fsafe-buffer-usage-suggestions %s 2>&1 | FileCheck %s
|
|
|
|
typedef int * TYPEDEF_PTR;
|
|
#define MACRO_PTR int*
|
|
|
|
// We CANNOT fix a pointer whose type is defined in a typedef or a
|
|
// macro. Because if the typedef is changed after the fix, the fix
|
|
// becomes incorrect and may not be noticed.
|
|
|
|
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE+1]]
|
|
void typedefPointer(TYPEDEF_PTR p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
if (++p) { // expected-note{{used in pointer arithmetic here}}
|
|
}
|
|
}
|
|
|
|
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE+1]]
|
|
void macroPointer(MACRO_PTR p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
if (++p) { // expected-note{{used in pointer arithmetic here}}
|
|
}
|
|
}
|
|
|
|
// The analysis requires accurate source location informations from
|
|
// `TypeLoc`s of types of variable (parameter) declarations in order
|
|
// to generate fix-its for them. But those information is not always
|
|
// available (probably due to some bugs in clang but it is irrelevant
|
|
// to the safe-buffer project). The following is an example. When
|
|
// `_Atomic` is used, we cannot get valid source locations of the
|
|
// pointee type of `unsigned *`. The analysis gives up in such a
|
|
// case.
|
|
// CHECK-NOT: fix-it:
|
|
void typeLocSourceLocationInvalid(_Atomic unsigned *map) { // expected-warning{{'map' is an unsafe pointer used for buffer access}}
|
|
map[5] = 5; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:33-[[@LINE+1]]:46}:"std::span<unsigned> map"
|
|
void typeLocSourceLocationValid(unsigned *map) { // expected-warning{{'map' is an unsafe pointer used for buffer access}} \
|
|
expected-note{{change type of 'map' to 'std::span' to preserve bounds information}}
|
|
map[5] = 5; // expected-note{{used in buffer access here}}
|
|
}
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void typeLocSourceLocationValid(unsigned *map) {return typeLocSourceLocationValid(std::span<unsigned>(map, <# size #>));}\n"
|
|
|
|
// We do not fix parameters participating unsafe operations for the
|
|
// following functions/methods or function-like expressions:
|
|
|
|
// CHECK-NOT: fix-it:
|
|
class A {
|
|
// constructor & descructor
|
|
A(int * p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
int tmp;
|
|
tmp = p[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
// class member methods
|
|
void foo(int *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
int tmp;
|
|
tmp = p[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
// overload operator
|
|
int operator+(int * p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
int tmp;
|
|
tmp = p[5]; // expected-note{{used in buffer access here}}
|
|
return tmp;
|
|
}
|
|
};
|
|
|
|
// lambdas
|
|
void foo() {
|
|
auto Lamb = [&](int *p) // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
-> int {
|
|
int tmp;
|
|
tmp = p[5]; // expected-note{{used in buffer access here}}
|
|
return tmp;
|
|
};
|
|
}
|
|
|
|
// template
|
|
template<typename T>
|
|
void template_foo(T * p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
T tmp;
|
|
tmp = p[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
void instantiate_template_foo() {
|
|
int * p;
|
|
template_foo(p); // FIXME expected note {{in instantiation of function template specialization 'template_foo<int>' requested here}}
|
|
}
|
|
|
|
// variadic function
|
|
void vararg_foo(int * p...) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
int tmp;
|
|
tmp = p[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
// constexpr functions
|
|
constexpr int constexpr_foo(int * p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
return p[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
// function body is a try-block
|
|
void fn_with_try_block(int* p) // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
try {
|
|
int tmp;
|
|
|
|
if (p == nullptr)
|
|
throw 42;
|
|
tmp = p[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
catch (int) {
|
|
*p = 0;
|
|
}
|
|
|
|
// The following two unsupported cases are not specific to
|
|
// parm-fixits. Adding them here in case they get forgotten.
|
|
void isArrayDecayToPointerUPC(int a[][10], int (*b)[10]) {
|
|
// expected-warning@-1{{'a' is an unsafe pointer used for buffer access}}
|
|
// expected-warning@-2{{'b' is an unsafe pointer used for buffer access}}
|
|
int tmp;
|
|
|
|
tmp = a[5][5] + b[5][5]; // expected-note2{{used in buffer access here}}
|
|
}
|
|
|
|
// parameter having default values:
|
|
void parmWithDefaultValue(int * x = 0) {
|
|
// expected-warning@-1{{'x' is an unsafe pointer used for buffer access}}
|
|
int tmp;
|
|
tmp = x[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
void parmWithDefaultValueDecl(int * x = 0);
|
|
|
|
void parmWithDefaultValueDecl(int * x) {
|
|
// expected-warning@-1{{'x' is an unsafe pointer used for buffer access}}
|
|
int tmp;
|
|
tmp = x[5]; // expected-note{{used in buffer access here}}
|
|
}
|
|
|
|
#define MACRO_NAME MyName
|
|
|
|
// The fix-it ends with a macro. It will be discarded due to overlap with macros.
|
|
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]
|
|
void macroIdentifier(int * MACRO_NAME) { // expected-warning{{'MyName' is an unsafe pointer used for buffer access}}
|
|
if (++MyName){} // expected-note{{used in pointer arithmetic here}}
|
|
}
|
|
|
|
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]
|
|
void parmHasNoName(int *p, int *) { // cannot fix the function because there is one parameter has no name. \
|
|
expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
|
p[5] = 5; // expected-note{{used in buffer access here}}
|
|
}
|