blob: 0c80da63f829126a86caf8415f02c28f9bc3c9f2 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
// 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}}
}
|