// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t #define offsetof(type, member) __builtin_offsetof(type, member) typedef __SIZE_TYPE__ size_t; typedef __WCHAR_TYPE__ wchar_t; extern void *memset(void *Dest, int Ch, size_t Count); extern size_t strlen(const char *Str); extern size_t wcslen(const wchar_t *Str); extern char *strcpy(char *Dest, const char *Src); extern wchar_t *wcscpy(wchar_t *Dest, const wchar_t *Src); extern int scanf(const char *Format, ...); extern int wscanf(const wchar_t *Format, ...); extern void sink(const void *P); enum { BufferSize = 1024 }; void bad1a(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + sizeof(Buffer)) { // 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] // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} *Q++ = 0; } } void bad1b(void) { typedef int Integer; Integer Buffer[BufferSize]; Integer *P = &Buffer[0]; Integer *Q = P; while (Q < P + sizeof(Buffer)) { // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(Integer)' == {{[0-9]+}} *Q++ = 0; } } void good1(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + BufferSize) { *Q++ = 0; } } void bad2(void) { int Buffer[BufferSize]; int *P = Buffer; while (P < Buffer + sizeof(Buffer)) { // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} *P++ = 0; } } void good2(void) { int Buffer[BufferSize]; int *P = Buffer; while (P < Buffer + BufferSize) { *P++ = 0; } } struct S { long A, B, C; }; void bad3a(struct S *S) { const size_t Offset = offsetof(struct S, B); struct S *P = S; // This is not captureable by Tidy because the size/offset expression is // not a direct child of the pointer arithmetics. memset(P + Offset, 0, sizeof(struct S) - Offset); } void good3a(struct S *S) { const size_t Offset = offsetof(struct S, B); char *P = (char*)S; // This is not captureable by Tidy because the size/offset expression is // not a direct child of the pointer arithmetics. memset(P + Offset, 0, sizeof(struct S) - Offset); } void bad3b(struct S *S) { memset(S + offsetof(struct S, B), 0, sizeof(struct S) - offsetof(struct S, B)); // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: suspicious usage of 'offsetof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator // CHECK-MESSAGES: :[[@LINE-3]]:12: note: '+' in pointer arithmetic internally scales with 'sizeof(struct S)' == {{[0-9]+}} } void good3b(struct S *S) { char *P = (char*)S; memset(P + offsetof(struct S, B), 0, sizeof(struct S) - offsetof(struct S, B)); } void bad3c(void) { struct S Buffer[BufferSize]; struct S *P = &Buffer[0]; struct S *Q = P; while (Q < P + sizeof(Buffer)) { // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(struct S)' == {{[0-9]+}} sink(Q++); } } void bad4(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + BufferSize) { *Q = 0; Q += sizeof(*Q); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+=' operator // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+=' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} } } void silenced4(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; char *Q = P; while (Q < P + BufferSize) { *Q = 0; Q += sizeof(*Q); } } void good4(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; char *Q = P; while (Q < P + BufferSize) { *Q = 0; Q += 1; } } void good5aa(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + BufferSize) { *Q = 0; Q += ( sizeof(Buffer) / sizeof(Buffer[0]) ); } } void good5ab(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + BufferSize) { *Q = 0; Q = Q + ( sizeof(Buffer) / sizeof(Buffer[0]) ); } } void good5ba(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + BufferSize) { *Q = 0; Q -= ( sizeof(Buffer) / sizeof(Buffer[0]) ); } } void good5bb(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + BufferSize) { *Q = 0; Q = Q - ( sizeof(Buffer) / sizeof(Buffer[0]) ); } } void bad6(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q < P + BufferSize) { *Q = 0; Q = Q + sizeof(*Q); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} } } void silenced6(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; char *Q = P; while (Q < P + BufferSize) { *Q = 0; Q = Q + sizeof(*Q); } } void good6(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; char *Q = P; while (Q < P + BufferSize) { *Q = 0; Q = Q + 1; } } void silenced7(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; const char *Q = P; while (Q < P + BufferSize) { sink(Q); Q = Q + sizeof(*Q); } } void good7(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; const char *Q = P; while (Q < P + BufferSize) { sink(Q); Q = Q + 1; } } void bad8(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P; while (Q >= P) { *Q = 0; Q = Q - sizeof(*Q); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '-' operator // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '-' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} } } void silenced8(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; char *Q = P; while (Q >= P) { *Q = 0; Q = Q - sizeof(*Q); } } void good8(void) { char Buffer[BufferSize]; char *P = &Buffer[0]; char *Q = P; while (Q >= P) { *Q = 0; Q = Q - 1; } } void good9(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = P + BufferSize; int N = Q - P; while (N >= 0) { Q[N] = 0; N = N - 1; } } void good10(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = Buffer + BufferSize; int I = sizeof(*P) - sizeof(*Q); sink(&I); } void good11(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; int *Q = Buffer + BufferSize; int I = sizeof(Q) - sizeof(*P); sink(&I); } void bad12(void) { wchar_t Message[BufferSize]; wcscpy(Message, L"Message: "); wscanf(L"%s", Message + wcslen(Message) * sizeof(wchar_t)); // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator // CHECK-MESSAGES: :[[@LINE-2]]:25: note: '+' in pointer arithmetic internally scales with 'sizeof(wchar_t)' == {{[0-9]+}} } void silenced12(void) { char Message[BufferSize]; strcpy(Message, "Message: "); scanf("%s", Message + strlen(Message) * sizeof(char)); } void nomatch12(void) { char Message[BufferSize]; strcpy(Message, "Message: "); scanf("%s", Message + strlen(Message)); } void good12(void) { wchar_t Message[BufferSize]; wcscpy(Message, L"Message: "); wscanf(L"%s", Message + wcslen(Message)); } void good13(void) { int Buffer[BufferSize]; int *P = &Buffer[0]; while (P < Buffer + sizeof(Buffer) / sizeof(int)) { // NO-WARNING: Calculating the element count of the buffer here, which is // safe with this idiom (as long as the types don't change). ++P; } while (P < Buffer + sizeof(Buffer) / sizeof(Buffer[0])) { // NO-WARNING: Calculating the element count of the buffer here, which is // safe with this idiom. ++P; } while (P < Buffer + sizeof(Buffer) / sizeof(*P)) { // NO-WARNING: Calculating the element count of the buffer here, which is // safe with this idiom. ++P; } } void situational14(int *Buffer, size_t BufferSize) { int *P = &Buffer[0]; while (P < Buffer + BufferSize / sizeof(*Buffer)) { // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}} ++P; } }