1 // RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- -config="{CheckOptions: {bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression: true, bugprone-sizeof-expression.WarnOnSizeOfPointer: true}}" --
2 
3 class C {
size()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 
AsBool()20 bool AsBool() { return false; }
AsInt()21 int AsInt() { return 0; }
AsEnum()22 E AsEnum() { return E_VALUE; }
AsEnumClass()23 EC AsEnumClass() { return EC::VALUE; }
AsStruct()24 S AsStruct() { return {}; }
25 
26 struct M {
AsIntM27   int AsInt() { return 0; }
AsEnumM28   E AsEnum() { return E_VALUE; }
AsStructM29   S AsStruct() { return {}; }
30 };
31 
Test1(const char * ptr)32 int Test1(const char* ptr) {
33   int sum = 0;
34   sum += sizeof(LEN);
35   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
36   sum += sizeof(LEN + 1);
37   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
38   sum += sizeof(sum, LEN);
39   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: suspicious usage of 'sizeof(..., ...)'
40   sum += sizeof(AsBool());
41   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
42   sum += sizeof(AsInt());
43   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
44   sum += sizeof(AsEnum());
45   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
46   sum += sizeof(AsEnumClass());
47   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
48   sum += sizeof(M{}.AsInt());
49   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
50   sum += sizeof(M{}.AsEnum());
51   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of integer type
52   sum += sizeof(sizeof(X));
53   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
54   sum += sizeof(LEN + sizeof(X));
55   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
56   sum += sizeof(LEN + LEN + sizeof(X));
57   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
58   sum += sizeof(LEN + (LEN + sizeof(X)));
59   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
60   sum += sizeof(LEN + -sizeof(X));
61   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
62   sum += sizeof(LEN + - + -sizeof(X));
63   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
64   sum += sizeof(char) / sizeof(char);
65   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
66   sum += sizeof(A) / sizeof(S);
67   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
68   sum += sizeof(char) / sizeof(int);
69   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
70   sum += sizeof(char) / sizeof(A);
71   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
72   sum += sizeof(B[0]) / sizeof(A);
73   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
74   sum += sizeof(ptr) / sizeof(char);
75   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
76   sum += sizeof(ptr) / sizeof(ptr[0]);
77   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
78   sum += sizeof(ptr) / sizeof(char*);
79   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
80   sum += sizeof(ptr) / sizeof(void*);
81   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
82   sum += sizeof(ptr) / sizeof(const void volatile*);
83   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
84   sum += sizeof(ptr) / sizeof(char);
85   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
86   sum += sizeof(int) * sizeof(char);
87   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious 'sizeof' by 'sizeof' multiplication
88   sum += sizeof(ptr) * sizeof(ptr[0]);
89   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
90   // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: suspicious 'sizeof' by 'sizeof' multiplication
91   sum += sizeof(int) * (2 * sizeof(char));
92   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious 'sizeof' by 'sizeof' multiplication
93   sum += (2 * sizeof(char)) * sizeof(int);
94   // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: suspicious 'sizeof' by 'sizeof' multiplication
95   if (sizeof(A) < 0x100000) sum += 42;
96   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: suspicious comparison of 'sizeof(expr)' to a constant
97   if (sizeof(A) <= 0xFFFFFFFEU) sum += 42;
98   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: suspicious comparison of 'sizeof(expr)' to a constant
99   return sum;
100 }
101 
Test5()102 int Test5() {
103   typedef int Array10[10];
104   typedef C ArrayC[10];
105 
106   struct MyStruct {
107     Array10 arr;
108     Array10* ptr;
109   };
110   typedef const MyStruct TMyStruct;
111   typedef const MyStruct *PMyStruct;
112   typedef TMyStruct *PMyStruct2;
113 
114   static TMyStruct kGlocalMyStruct = {};
115   static TMyStruct volatile * kGlocalMyStructPtr = &kGlocalMyStruct;
116 
117   MyStruct S;
118   PMyStruct PS;
119   PMyStruct2 PS2;
120   Array10 A10;
121   C *PtrArray[10];
122   C *PC;
123 
124   char *PChar;
125   int *PInt, **PPInt;
126   MyStruct **PPMyStruct;
127 
128   int sum = 0;
129   sum += sizeof(&S.arr);
130   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
131   sum += sizeof(&kGlocalMyStruct.arr);
132   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
133   sum += sizeof(&kGlocalMyStructPtr->arr);
134   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
135   sum += sizeof(S.arr + 0);
136   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
137   sum += sizeof(+ S.arr);
138   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
139   sum += sizeof((int*)S.arr);
140   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
141 
142   sum += sizeof(S.ptr);
143   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
144   sum += sizeof(kGlocalMyStruct.ptr);
145   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
146   sum += sizeof(kGlocalMyStructPtr->ptr);
147   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
148 
149   sum += sizeof(&kGlocalMyStruct);
150   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
151   sum += sizeof(&S);
152   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
153   sum += sizeof(MyStruct*);
154   sum += sizeof(PMyStruct);
155   sum += sizeof(PS);
156   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
157   sum += sizeof(PS2);
158   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
159   sum += sizeof(&A10);
160   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
161   sum += sizeof(PtrArray) / sizeof(PtrArray[1]);
162   // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: suspicious usage of 'sizeof()' on an expression of pointer type
163   sum += sizeof(A10) / sizeof(PtrArray[0]);
164   sum += sizeof(PC) / sizeof(PtrArray[0]);
165   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
166   // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions have the same type
167   sum += sizeof(ArrayC) / sizeof(PtrArray[0]);
168   // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
169 
170   sum += sizeof(PChar);
171   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
172   sum += sizeof(PInt);
173   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
174   sum += sizeof(PPInt);
175   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
176   sum += sizeof(PPMyStruct);
177   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
178 
179   return sum;
180 }
181 
182 void some_generic_function(const void *arg, int argsize);
183 int *IntP, **IntPP;
184 C *ClassP, **ClassPP;
185 
GenericFunctionTest()186 void GenericFunctionTest() {
187   // The `sizeof(pointer)` checks ignore situations where the pointer is
188   // produced by dereferencing a pointer-to-pointer, because this is unlikely
189   // to be an accident and can appear in legitimate code that tries to call
190   // a generic function which emulates dynamic typing within C.
191   some_generic_function(IntPP, sizeof(*IntPP));
192   some_generic_function(ClassPP, sizeof(*ClassPP));
193   // Using `...[0]` instead of the dereference operator is another common
194   // variant, which is also widespread in the idiomatic array-size calculation:
195   // `sizeof(array) / sizeof(array[0])`.
196   some_generic_function(IntPP, sizeof(IntPP[0]));
197   some_generic_function(ClassPP, sizeof(ClassPP[0]));
198   // FIXME: There is a third common pattern where the generic function is
199   // called with `&Variable` and `sizeof(Variable)`. Right now these are
200   // reported by the `sizeof(pointer)` checks, but this causes some false
201   // positives, so it would be good to create an exception for them.
202   some_generic_function(&IntPP, sizeof(IntP));
203   // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: suspicious usage of 'sizeof()' on an expression of pointer type
204   some_generic_function(&ClassPP, sizeof(ClassP));
205   // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: suspicious usage of 'sizeof()' on an expression of pointer type
206 }
207 
ValidExpressions()208 int ValidExpressions() {
209   int A[] = {1, 2, 3, 4};
210   static const char str[] = "hello";
211   static const char* ptr[] { "aaa", "bbb", "ccc" };
212   typedef C *CA10[10];
213   C *PtrArray[10];
214   CA10 PtrArray1;
215 
216   int sum = 0;
217   if (sizeof(A) < 10)
218     sum += sizeof(A);
219   sum += sizeof(int);
220   sum += sizeof(AsStruct());
221   sum += sizeof(M{}.AsStruct());
222   sum += sizeof(A[sizeof(A) / sizeof(int)]);
223   // Here the outer sizeof is reported, but the inner ones are accepted:
224   sum += sizeof(&A[sizeof(A) / sizeof(int)]);
225   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression of pointer type
226   sum += sizeof(sizeof(0));  // Special case: sizeof size_t.
227   sum += sizeof(void*);
228   sum += sizeof(void const *);
229   sum += sizeof(void const *) / 4;
230   sum += sizeof(str);
231   sum += sizeof(str) / sizeof(char);
232   sum += sizeof(str) / sizeof(str[0]);
233   sum += sizeof(ptr) / sizeof(ptr[0]);
234   sum += sizeof(ptr) / sizeof(*(ptr));
235   sum += sizeof(PtrArray) / sizeof(PtrArray[0]);
236   // Canonical type of PtrArray1 is same as PtrArray.
237   sum = sizeof(PtrArray) / sizeof(PtrArray1[0]);
238   // There is no warning for 'sizeof(T*)/sizeof(Q)' case.
239   sum += sizeof(PtrArray) / sizeof(A[0]);
240   return sum;
241 }
242