xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.cpp (revision e855feac41fd89aebf540a155d21f12a3e82f05b)
1 // RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- -config="{CheckOptions: {bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression: true}}" --
2 
3 class C {
4   int size() { return sizeof(this); }
5   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(this)'
6 };
7 
8 #define LEN 8
9 
10 int X;
11 extern int A[10];
12 extern short B[10];
13 
14 #pragma pack(1)
15 struct  S { char a, b, c; };
16 
17 enum E { E_VALUE = 0 };
18 enum class EC { VALUE = 0 };
19 
20 bool AsBool() { return false; }
21 int AsInt() { return 0; }
22 E AsEnum() { return E_VALUE; }
23 EC AsEnumClass() { return EC::VALUE; }
24 S AsStruct() { return {}; }
25 
26 struct M {
27   int AsInt() { return 0; }
28   E AsEnum() { return E_VALUE; }
29   S AsStruct() { return {}; }
30 };
31 
32 int ReturnOverload(int) { return {}; }
33 S ReturnOverload(S) { return {}; }
34 
35 template <class T>
36 T ReturnTemplate(T) { return {}; }
37 
38 template <class T>
39 bool TestTrait1() {
40   return sizeof(ReturnOverload(T{})) == sizeof(A);
41 }
42 
43 template <class T>
44 bool TestTrait2() {
45   return sizeof(ReturnTemplate(T{})) == sizeof(A);
46 }
47 
48 template <class T>
49 bool TestTrait3() {
50   return sizeof(ReturnOverload(0)) == sizeof(T{});
51   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
52 }
53 
54 template <class T>
55 bool TestTrait4() {
56   return sizeof(ReturnTemplate(0)) == sizeof(T{});
57   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
58 }
59 
60 bool TestTemplates() {
61   bool b = true;
62   b &= TestTrait1<int>();
63   b &= TestTrait1<S>();
64   b &= TestTrait2<int>();
65   b &= TestTrait2<S>();
66   b &= TestTrait3<int>();
67   b &= TestTrait3<S>();
68   b &= TestTrait4<int>();
69   b &= TestTrait4<S>();
70   return b;
71 }
72 
73 int Test1(const char* ptr) {
74   int sum = 0;
75   sum += sizeof(LEN);
76   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
77   sum += sizeof(LEN + 1);
78   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
79   sum += sizeof(sum, LEN);
80   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: suspicious usage of 'sizeof(..., ...)'
81   sum += sizeof(AsBool());
82   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
83   sum += sizeof(AsInt());
84   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
85   sum += sizeof(AsEnum());
86   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
87   sum += sizeof(AsEnumClass());
88   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
89   sum += sizeof(M{}.AsInt());
90   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
91   sum += sizeof(M{}.AsEnum());
92   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
93   sum += sizeof(sizeof(X));
94   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
95   sum += sizeof(LEN + sizeof(X));
96   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
97   sum += sizeof(LEN + LEN + sizeof(X));
98   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
99   sum += sizeof(LEN + (LEN + sizeof(X)));
100   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
101   sum += sizeof(LEN + -sizeof(X));
102   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
103   sum += sizeof(LEN + - + -sizeof(X));
104   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
105   sum += sizeof(char) / sizeof(char);
106   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
107   sum += sizeof(A) / sizeof(S);
108   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
109   sum += sizeof(char) / sizeof(int);
110   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
111   sum += sizeof(char) / sizeof(A);
112   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
113   sum += sizeof(B[0]) / sizeof(A);
114   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
115   sum += sizeof(ptr) / sizeof(char);
116   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer is divided by size of pointed type
117   sum += sizeof(ptr) / sizeof(ptr[0]);
118   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer is divided by size of pointed type
119   sum += sizeof(ptr) / sizeof(char*);
120   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have pointer types
121   sum += sizeof(ptr) / sizeof(void*);
122   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have pointer types
123   sum += sizeof(ptr) / sizeof(const void volatile*);
124   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have pointer types
125   sum += sizeof(ptr) / sizeof(char);
126   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer is divided by size of pointed type
127   sum += sizeof(int) * sizeof(char);
128   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious 'sizeof' by 'sizeof' multiplication
129   sum += sizeof(ptr) * sizeof(ptr[0]);
130   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious 'sizeof' by 'sizeof' multiplication
131   sum += sizeof(int) * (2 * sizeof(char));
132   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious 'sizeof' by 'sizeof' multiplication
133   sum += (2 * sizeof(char)) * sizeof(int);
134   // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: suspicious 'sizeof' by 'sizeof' multiplication
135   if (sizeof(A) < 0x100000) sum += 42;
136   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: suspicious comparison of 'sizeof(expr)' to a constant
137   if (sizeof(A) <= 0xFFFFFFFEU) sum += 42;
138   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: suspicious comparison of 'sizeof(expr)' to a constant
139   return sum;
140 }
141 
142 typedef char MyChar;
143 typedef const MyChar MyConstChar;
144 
145 int CE0 = sizeof sizeof(char);
146 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
147 int CE1 = sizeof +sizeof(char);
148 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
149 int CE2 = sizeof sizeof(const char*);
150 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
151 int CE3 = sizeof sizeof(const volatile char* const*);
152 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
153 int CE4 = sizeof sizeof(MyConstChar);
154 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
155 
156 int Test2(MyConstChar* A) {
157   int sum = 0;
158   sum += sizeof(MyConstChar) / sizeof(char);
159   // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
160   sum += sizeof(MyConstChar) / sizeof(MyChar);
161   // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
162   sum += sizeof(A[0]) / sizeof(char);
163   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
164   return sum;
165 }
166 
167 template <int T>
168 int Foo() { int A[T]; return sizeof(T); }
169 // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: suspicious usage of 'sizeof(K)'
170 template <typename T>
171 int Bar() { T A[5]; return sizeof(A[0]) / sizeof(T); }
172 // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
173 int Test3() { return Foo<42>() + Bar<char>(); }
174 
175 static const char* kABC = "abc";
176 static const wchar_t* kDEF = L"def";
177 int Test4(const char A[10]) {
178   int sum = 0;
179   sum += sizeof(kABC);
180   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(char*)'
181   sum += sizeof(kDEF);
182   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(char*)'
183   return sum;
184 }
185 
186 int Test5() {
187   typedef int Array10[10];
188   typedef C ArrayC[10];
189 
190   struct MyStruct {
191     Array10 arr;
192     Array10* ptr;
193   };
194   typedef const MyStruct TMyStruct;
195   typedef const MyStruct *PMyStruct;
196   typedef TMyStruct *PMyStruct2;
197 
198   static TMyStruct kGlocalMyStruct = {};
199   static TMyStruct volatile * kGlocalMyStructPtr = &kGlocalMyStruct;
200 
201   MyStruct S;
202   PMyStruct PS;
203   PMyStruct2 PS2;
204   Array10 A10;
205   C *PtrArray[10];
206   C *PC;
207 
208   char *PChar;
209   int *PInt, **PPInt;
210   MyStruct **PPMyStruct;
211 
212   int sum = 0;
213   sum += sizeof(&S.arr);
214   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
215   sum += sizeof(&kGlocalMyStruct.arr);
216   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
217   sum += sizeof(&kGlocalMyStructPtr->arr);
218   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
219   sum += sizeof(S.arr + 0);
220   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
221   sum += sizeof(+ S.arr);
222   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
223   sum += sizeof((int*)S.arr);
224   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
225 
226   sum += sizeof(S.ptr);
227   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
228   sum += sizeof(kGlocalMyStruct.ptr);
229   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
230   sum += sizeof(kGlocalMyStructPtr->ptr);
231   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
232 
233   sum += sizeof(&kGlocalMyStruct);
234   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
235   sum += sizeof(&S);
236   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
237   sum += sizeof(MyStruct*);
238   sum += sizeof(PMyStruct);
239   sum += sizeof(PS);
240   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
241   sum += sizeof(PS2);
242   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
243   sum += sizeof(&A10);
244   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
245   sum += sizeof(PtrArray) / sizeof(PtrArray[1]);
246   // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: suspicious usage of 'sizeof()' on an expression of pointer type
247   sum += sizeof(A10) / sizeof(PtrArray[0]);
248   sum += sizeof(PC) / sizeof(PtrArray[0]);
249   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
250   // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
251   sum += sizeof(ArrayC) / sizeof(PtrArray[0]);
252   // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
253 
254   // These pointers do not point to aggregate types, so they are not reported in this mode:
255   sum += sizeof(PChar);
256   sum += sizeof(PInt);
257   sum += sizeof(PPInt);
258   sum += sizeof(PPMyStruct);
259 
260   return sum;
261 }
262 
263 int Test6() {
264   int sum = 0;
265 
266   struct S A = AsStruct(), B = AsStruct();
267   struct S *P = &A, *Q = &B;
268   sum += sizeof(struct S) == P - Q;
269   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
270   sum += 5 * sizeof(S) != P - Q;
271   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
272   sum += sizeof(S) < P - Q;
273   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
274   sum += 5 * sizeof(S) <= P - Q;
275   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
276   sum += 5 * sizeof(*P) >= P - Q;
277   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
278   sum += Q - P > 3 * sizeof(*P);
279   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
280   sum += sizeof(S) + (P - Q);
281   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
282   sum += 5 * sizeof(S) - (P - Q);
283   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
284   sum += (P - Q) / sizeof(S);
285   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
286   sum += (P - Q) / sizeof(*Q);
287   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
288 
289   return sum;
290 }
291 
292 static constexpr inline int BufferSize = 1024;
293 
294 template <typename T>
295 T next(const T *&Read) {
296   T value = *Read;
297   Read += sizeof(T);
298   return value;
299 }
300 
301 void Test7() {
302   int Buffer[BufferSize];
303   int *P = &Buffer[0];
304 
305   const int *P2 = P;
306   int V1 = next(P2);
307   // CHECK-MESSAGES: :[[@LINE-10]]:8: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+=' operator
308   // CHECK-MESSAGES: :[[@LINE-11]]:8: note: '+=' in pointer arithmetic internally scales with 'sizeof(const int)' == {{[0-9]+}}
309   int V2 = next(P2);
310   (void)V1;
311   (void)V2;
312 
313   int *Q = P;
314   while (Q < P + sizeof(Buffer)) {
315     // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
316     // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}}
317     *Q++ = 0;
318   }
319 }
320 
321 #ifdef __SIZEOF_INT128__
322 template <__int128_t N>
323 #else
324 template <long N> // Fallback for platforms which do not define `__int128_t`
325 #endif
326 bool Baz() { return sizeof(A) < N; }
327 // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: suspicious comparison of 'sizeof(expr)' to a constant
328 bool Test8() { return Baz<-1>(); }
329 
330 void some_generic_function(const void *arg, int argsize);
331 int *IntP, **IntPP;
332 C *ClassP, **ClassPP;
333 
334 void GenericFunctionTest() {
335   // The `sizeof(pointer)` checks ignore situations where the pointer is
336   // produced by dereferencing a pointer-to-pointer, because this is unlikely
337   // to be an accident and can appear in legitimate code that tries to call
338   // a generic function which emulates dynamic typing within C.
339   some_generic_function(IntPP, sizeof(*IntPP));
340   some_generic_function(ClassPP, sizeof(*ClassPP));
341   // Using `...[0]` instead of the dereference operator is another common
342   // variant, which is also widespread in the idiomatic array-size calculation:
343   // `sizeof(array) / sizeof(array[0])`.
344   some_generic_function(IntPP, sizeof(IntPP[0]));
345   some_generic_function(ClassPP, sizeof(ClassPP[0]));
346   // FIXME: There is a third common pattern where the generic function is
347   // called with `&Variable` and `sizeof(Variable)`. Right now these are
348   // reported by the `sizeof(pointer)` checks, but this causes some false
349   // positives, so it would be good to create an exception for them.
350   // NOTE: `sizeof(IntP)` is only reported with `WarnOnSizeOfPointer=true`.
351   some_generic_function(&IntPP, sizeof(IntP));
352   some_generic_function(&ClassPP, sizeof(ClassP));
353   // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: suspicious usage of 'sizeof()' on an expression of pointer type
354 }
355 
356 int ValidExpressions() {
357   int A[] = {1, 2, 3, 4};
358   static const char str[] = "hello";
359   static const char* ptr[] { "aaa", "bbb", "ccc" };
360   typedef C *CA10[10];
361   C *PtrArray[10];
362   CA10 PtrArray1;
363 
364   int sum = 0;
365   if (sizeof(A) < 10)
366     sum += sizeof(A);
367   sum += sizeof(int);
368   sum += sizeof(AsStruct());
369   sum += sizeof(M{}.AsStruct());
370   sum += sizeof(A[sizeof(A) / sizeof(int)]);
371   sum += sizeof(&A[sizeof(A) / sizeof(int)]);
372   sum += sizeof(sizeof(0));  // Special case: sizeof size_t.
373   sum += sizeof(void*);
374   sum += sizeof(void const *);
375   sum += sizeof(void const *) / 4;
376   sum += sizeof(str);
377   sum += sizeof(str) / sizeof(char);
378   sum += sizeof(str) / sizeof(str[0]);
379   sum += sizeof(ptr) / sizeof(ptr[0]);
380   sum += sizeof(ptr) / sizeof(*(ptr));
381   sum += sizeof(PtrArray) / sizeof(PtrArray[0]);
382   // Canonical type of PtrArray1 is same as PtrArray.
383   sum = sizeof(PtrArray) / sizeof(PtrArray1[0]);
384   // There is no warning for 'sizeof(T*)/sizeof(Q)' case.
385   sum += sizeof(PtrArray) / sizeof(A[0]);
386   return sum;
387 }
388 
389 namespace gh115175 {
390 template<class T>
391 int ValidateTemplateTypeExpressions(T t) {
392   return sizeof(t.val) / sizeof(t.val[0]);
393 }
394 } // namespace gh115175
395