1 // RUN: %check_clang_tidy %s bugprone-sizeof-expression %t 2 3 #define offsetof(type, member) __builtin_offsetof(type, member) 4 5 typedef __SIZE_TYPE__ size_t; 6 typedef __WCHAR_TYPE__ wchar_t; 7 8 extern void *memset(void *Dest, int Ch, size_t Count); 9 extern size_t strlen(const char *Str); 10 extern size_t wcslen(const wchar_t *Str); 11 extern char *strcpy(char *Dest, const char *Src); 12 extern wchar_t *wcscpy(wchar_t *Dest, const wchar_t *Src); 13 extern int scanf(const char *Format, ...); 14 extern int wscanf(const wchar_t *Format, ...); 15 16 extern void sink(const void *P); 17 18 enum { BufferSize = 1024 }; 19 20 void bad1a(void) { 21 int Buffer[BufferSize]; 22 23 int *P = &Buffer[0]; 24 int *Q = P; 25 while (Q < P + sizeof(Buffer)) { 26 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator [bugprone-sizeof-expression] 27 // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} 28 *Q++ = 0; 29 } 30 } 31 32 void bad1b(void) { 33 typedef int Integer; 34 Integer Buffer[BufferSize]; 35 36 Integer *P = &Buffer[0]; 37 Integer *Q = P; 38 while (Q < P + sizeof(Buffer)) { 39 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator 40 // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(Integer)' == {{[0-9]+}} 41 *Q++ = 0; 42 } 43 } 44 45 void good1(void) { 46 int Buffer[BufferSize]; 47 48 int *P = &Buffer[0]; 49 int *Q = P; 50 while (Q < P + BufferSize) { 51 *Q++ = 0; 52 } 53 } 54 55 void bad2(void) { 56 int Buffer[BufferSize]; 57 int *P = Buffer; 58 59 while (P < Buffer + sizeof(Buffer)) { 60 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator 61 // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} 62 *P++ = 0; 63 } 64 } 65 66 void good2(void) { 67 int Buffer[BufferSize]; 68 int *P = Buffer; 69 70 while (P < Buffer + BufferSize) { 71 *P++ = 0; 72 } 73 } 74 75 struct S { 76 long A, B, C; 77 }; 78 79 void bad3a(struct S *S) { 80 const size_t Offset = offsetof(struct S, B); 81 struct S *P = S; 82 83 // This is not captureable by Tidy because the size/offset expression is 84 // not a direct child of the pointer arithmetics. 85 memset(P + Offset, 0, sizeof(struct S) - Offset); 86 } 87 88 void good3a(struct S *S) { 89 const size_t Offset = offsetof(struct S, B); 90 char *P = (char*)S; 91 92 // This is not captureable by Tidy because the size/offset expression is 93 // not a direct child of the pointer arithmetics. 94 memset(P + Offset, 0, sizeof(struct S) - Offset); 95 } 96 97 void bad3b(struct S *S) { 98 memset(S + offsetof(struct S, B), 0, 99 sizeof(struct S) - offsetof(struct S, B)); 100 // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: suspicious usage of 'offsetof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator 101 // CHECK-MESSAGES: :[[@LINE-3]]:12: note: '+' in pointer arithmetic internally scales with 'sizeof(struct S)' == {{[0-9]+}} 102 } 103 104 void good3b(struct S *S) { 105 char *P = (char*)S; 106 memset(P + offsetof(struct S, B), 0, 107 sizeof(struct S) - offsetof(struct S, B)); 108 } 109 110 void bad3c(void) { 111 struct S Buffer[BufferSize]; 112 113 struct S *P = &Buffer[0]; 114 struct S *Q = P; 115 while (Q < P + sizeof(Buffer)) { 116 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator 117 // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(struct S)' == {{[0-9]+}} 118 sink(Q++); 119 } 120 } 121 122 void bad4(void) { 123 int Buffer[BufferSize]; 124 125 int *P = &Buffer[0]; 126 int *Q = P; 127 while (Q < P + BufferSize) { 128 *Q = 0; 129 Q += sizeof(*Q); 130 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+=' operator 131 // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+=' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} 132 } 133 } 134 135 void silenced4(void) { 136 char Buffer[BufferSize]; 137 138 char *P = &Buffer[0]; 139 char *Q = P; 140 while (Q < P + BufferSize) { 141 *Q = 0; 142 Q += sizeof(*Q); 143 } 144 } 145 146 void good4(void) { 147 char Buffer[BufferSize]; 148 149 char *P = &Buffer[0]; 150 char *Q = P; 151 while (Q < P + BufferSize) { 152 *Q = 0; 153 Q += 1; 154 } 155 } 156 157 void good5aa(void) { 158 int Buffer[BufferSize]; 159 160 int *P = &Buffer[0]; 161 int *Q = P; 162 while (Q < P + BufferSize) { 163 *Q = 0; 164 Q += ( sizeof(Buffer) / sizeof(Buffer[0]) ); 165 } 166 } 167 168 void good5ab(void) { 169 int Buffer[BufferSize]; 170 171 int *P = &Buffer[0]; 172 int *Q = P; 173 while (Q < P + BufferSize) { 174 *Q = 0; 175 Q = Q + ( sizeof(Buffer) / sizeof(Buffer[0]) ); 176 } 177 } 178 179 void good5ba(void) { 180 int Buffer[BufferSize]; 181 182 int *P = &Buffer[0]; 183 int *Q = P; 184 while (Q < P + BufferSize) { 185 *Q = 0; 186 Q -= ( sizeof(Buffer) / sizeof(Buffer[0]) ); 187 } 188 } 189 190 void good5bb(void) { 191 int Buffer[BufferSize]; 192 193 int *P = &Buffer[0]; 194 int *Q = P; 195 while (Q < P + BufferSize) { 196 *Q = 0; 197 Q = Q - ( sizeof(Buffer) / sizeof(Buffer[0]) ); 198 } 199 } 200 201 void bad6(void) { 202 int Buffer[BufferSize]; 203 204 int *P = &Buffer[0]; 205 int *Q = P; 206 while (Q < P + BufferSize) { 207 *Q = 0; 208 Q = Q + sizeof(*Q); 209 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator 210 // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} 211 } 212 } 213 214 void silenced6(void) { 215 char Buffer[BufferSize]; 216 217 char *P = &Buffer[0]; 218 char *Q = P; 219 while (Q < P + BufferSize) { 220 *Q = 0; 221 Q = Q + sizeof(*Q); 222 } 223 } 224 225 void good6(void) { 226 char Buffer[BufferSize]; 227 228 char *P = &Buffer[0]; 229 char *Q = P; 230 while (Q < P + BufferSize) { 231 *Q = 0; 232 Q = Q + 1; 233 } 234 } 235 236 void silenced7(void) { 237 char Buffer[BufferSize]; 238 239 char *P = &Buffer[0]; 240 const char *Q = P; 241 while (Q < P + BufferSize) { 242 sink(Q); 243 Q = Q + sizeof(*Q); 244 } 245 } 246 247 void good7(void) { 248 char Buffer[BufferSize]; 249 250 char *P = &Buffer[0]; 251 const char *Q = P; 252 while (Q < P + BufferSize) { 253 sink(Q); 254 Q = Q + 1; 255 } 256 } 257 258 void bad8(void) { 259 int Buffer[BufferSize]; 260 261 int *P = &Buffer[0]; 262 int *Q = P; 263 while (Q >= P) { 264 *Q = 0; 265 Q = Q - sizeof(*Q); 266 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '-' operator 267 // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '-' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} 268 } 269 } 270 271 void silenced8(void) { 272 char Buffer[BufferSize]; 273 274 char *P = &Buffer[0]; 275 char *Q = P; 276 while (Q >= P) { 277 *Q = 0; 278 Q = Q - sizeof(*Q); 279 } 280 } 281 282 void good8(void) { 283 char Buffer[BufferSize]; 284 285 char *P = &Buffer[0]; 286 char *Q = P; 287 while (Q >= P) { 288 *Q = 0; 289 Q = Q - 1; 290 } 291 } 292 293 void good9(void) { 294 int Buffer[BufferSize]; 295 296 int *P = &Buffer[0]; 297 int *Q = P + BufferSize; 298 int N = Q - P; 299 while (N >= 0) { 300 Q[N] = 0; 301 N = N - 1; 302 } 303 } 304 305 void good10(void) { 306 int Buffer[BufferSize]; 307 308 int *P = &Buffer[0]; 309 int *Q = Buffer + BufferSize; 310 int I = sizeof(*P) - sizeof(*Q); 311 312 sink(&I); 313 } 314 315 void good11(void) { 316 int Buffer[BufferSize]; 317 318 int *P = &Buffer[0]; 319 int *Q = Buffer + BufferSize; 320 int I = sizeof(Q) - sizeof(*P); 321 322 sink(&I); 323 } 324 325 void bad12(void) { 326 wchar_t Message[BufferSize]; 327 wcscpy(Message, L"Message: "); 328 wscanf(L"%s", Message + wcslen(Message) * sizeof(wchar_t)); 329 // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator 330 // CHECK-MESSAGES: :[[@LINE-2]]:25: note: '+' in pointer arithmetic internally scales with 'sizeof(wchar_t)' == {{[0-9]+}} 331 } 332 333 void silenced12(void) { 334 char Message[BufferSize]; 335 strcpy(Message, "Message: "); 336 scanf("%s", Message + strlen(Message) * sizeof(char)); 337 } 338 339 void nomatch12(void) { 340 char Message[BufferSize]; 341 strcpy(Message, "Message: "); 342 scanf("%s", Message + strlen(Message)); 343 } 344 345 void good12(void) { 346 wchar_t Message[BufferSize]; 347 wcscpy(Message, L"Message: "); 348 wscanf(L"%s", Message + wcslen(Message)); 349 } 350 351 void good13(void) { 352 int Buffer[BufferSize]; 353 354 int *P = &Buffer[0]; 355 while (P < Buffer + sizeof(Buffer) / sizeof(int)) { 356 // NO-WARNING: Calculating the element count of the buffer here, which is 357 // safe with this idiom (as long as the types don't change). 358 ++P; 359 } 360 361 while (P < Buffer + sizeof(Buffer) / sizeof(Buffer[0])) { 362 // NO-WARNING: Calculating the element count of the buffer here, which is 363 // safe with this idiom. 364 ++P; 365 } 366 367 while (P < Buffer + sizeof(Buffer) / sizeof(*P)) { 368 // NO-WARNING: Calculating the element count of the buffer here, which is 369 // safe with this idiom. 370 ++P; 371 } 372 } 373 374 void situational14(int *Buffer, size_t BufferSize) { 375 int *P = &Buffer[0]; 376 while (P < Buffer + BufferSize / sizeof(*Buffer)) { 377 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator 378 // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} 379 ++P; 380 } 381 } 382