xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp (revision 9c50182bf4942f88cc9876eb29e70802448cddc8)
1 // RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -fcxx-exceptions -fsafe-buffer-usage-suggestions -verify %s
2 // RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fcxx-exceptions -fdiagnostics-parseable-fixits -fsafe-buffer-usage-suggestions %s 2>&1 | FileCheck %s
3 
4 typedef int * TYPEDEF_PTR;
5 #define MACRO_PTR int*
6 
7 // We CANNOT fix a pointer whose type is defined in a typedef or a
8 // macro. Because if the typedef is changed after the fix, the fix
9 // becomes incorrect and may not be noticed.
10 
11 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE+1]]
12 void typedefPointer(TYPEDEF_PTR p) {  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
13   if (++p) {  // expected-note{{used in pointer arithmetic here}}
14   }
15 }
16 
17 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE+1]]
18 void macroPointer(MACRO_PTR p) {  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
19   if (++p) {  // expected-note{{used in pointer arithmetic here}}
20   }
21 }
22 
23 // The analysis requires accurate source location informations from
24 // `TypeLoc`s of types of variable (parameter) declarations in order
25 // to generate fix-its for them. But those information is not always
26 // available (probably due to some bugs in clang but it is irrelevant
27 // to the safe-buffer project).  The following is an example.  When
28 // `_Atomic` is used, we cannot get valid source locations of the
29 // pointee type of `unsigned *`.  The analysis gives up in such a
30 // case.
31 // CHECK-NOT: fix-it:
32 void typeLocSourceLocationInvalid(_Atomic unsigned *map) { // expected-warning{{'map' is an unsafe pointer used for buffer access}}
33   map[5] = 5; // expected-note{{used in buffer access here}}
34 }
35 
36 // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:33-[[@LINE+1]]:46}:"std::span<unsigned> map"
37 void typeLocSourceLocationValid(unsigned *map) { // expected-warning{{'map' is an unsafe pointer used for buffer access}} \
38 						    expected-note{{change type of 'map' to 'std::span' to preserve bounds information}}
39   map[5] = 5; // expected-note{{used in buffer access here}}
40 }
41 // 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"
42 
43 // We do not fix parameters participating unsafe operations for the
44 // following functions/methods or function-like expressions:
45 
46 // CHECK-NOT: fix-it:
47 class A {
48   // constructor & descructor
49   A(int * p) {  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
50     int tmp;
51     tmp = p[5]; // expected-note{{used in buffer access here}}
52   }
53 
54   // class member methods
55   void foo(int *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
56     int tmp;
57     tmp = p[5];      // expected-note{{used in buffer access here}}
58   }
59 
60   // overload operator
61   int operator+(int * p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
62     int tmp;
63     tmp = p[5];            // expected-note{{used in buffer access here}}
64     return tmp;
65   }
66 };
67 
68 // lambdas
69 void foo() {
70   auto Lamb = [&](int *p) // expected-warning{{'p' is an unsafe pointer used for buffer access}}
71     -> int {
72     int tmp;
73     tmp = p[5];           // expected-note{{used in buffer access here}}
74     return tmp;
75   };
76 }
77 
78 // template
79 template<typename T>
80 void template_foo(T * p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
81   T tmp;
82   tmp = p[5];              // expected-note{{used in buffer access here}}
83 }
84 
85 void instantiate_template_foo() {
86   int * p;
87   template_foo(p);        // FIXME expected note {{in instantiation of function template specialization 'template_foo<int>' requested here}}
88 }
89 
90 // variadic function
91 void vararg_foo(int * p...) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
92   int tmp;
93   tmp = p[5];                 // expected-note{{used in buffer access here}}
94 }
95 
96 // constexpr functions
97 constexpr int constexpr_foo(int * p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}
98   return p[5];                         // expected-note{{used in buffer access here}}
99 }
100 
101 // function body is a try-block
102 void fn_with_try_block(int* p)    // expected-warning{{'p' is an unsafe pointer used for buffer access}}
103   try {
104     int tmp;
105 
106     if (p == nullptr)
107       throw 42;
108     tmp = p[5];                   // expected-note{{used in buffer access here}}
109   }
110   catch (int) {
111     *p = 0;
112   }
113 
114 // The following two unsupported cases are not specific to
115 // parm-fixits. Adding them here in case they get forgotten.
116 void isArrayDecayToPointerUPC(int a[][10], int (*b)[10]) {
117 // expected-warning@-1{{'a' is an unsafe pointer used for buffer access}}
118 // expected-warning@-2{{'b' is an unsafe pointer used for buffer access}}
119   int tmp;
120 
121   tmp = a[5][5] + b[5][5];  // expected-note2{{used in buffer access here}}
122 }
123 
124 // parameter having default values:
125 void parmWithDefaultValue(int * x = 0) {
126   // expected-warning@-1{{'x' is an unsafe pointer used for buffer access}}
127   int tmp;
128   tmp = x[5]; // expected-note{{used in buffer access here}}
129 }
130 
131 void parmWithDefaultValueDecl(int * x = 0);
132 
133 void parmWithDefaultValueDecl(int * x) {
134   // expected-warning@-1{{'x' is an unsafe pointer used for buffer access}}
135   int tmp;
136   tmp = x[5]; // expected-note{{used in buffer access here}}
137 }
138 
139 #define MACRO_NAME MyName
140 
141 // The fix-it ends with a macro. It will be discarded due to overlap with macros.
142 // CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]
143 void macroIdentifier(int * MACRO_NAME) { // expected-warning{{'MyName' is an unsafe pointer used for buffer access}}
144   if (++MyName){} // expected-note{{used in pointer arithmetic here}}
145 }
146 
147 // CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]
148 void parmHasNoName(int *p, int *) { // cannot fix the function because there is one parameter has no name. \
149 				       expected-warning{{'p' is an unsafe pointer used for buffer access}}
150   p[5] = 5; // expected-note{{used in buffer access here}}
151 }
152