| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| .. title:: clang-tidy - cert-arr39-c | ||
| .. meta:: | ||
| :http-equiv=refresh: 5;URL=../bugprone/sizeof-expression.html | ||
|
|
||
| cert-arr39-c | ||
| ============ | ||
|
|
||
| The `cert-arr39-c` check is an alias, please see | ||
| :doc:`bugprone-sizeof-expression <../bugprone/sizeof-expression>` | ||
| for more information. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -103,7 +103,7 @@ Options | |
|
|
||
| int i = -42; | ||
| unsigned int u = 0xffffffff; | ||
| printf("%u %d\n", i, u); | ||
|
|
||
| would be converted to: | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,6 @@ Contents | |
| clang-include-fixer | ||
| modularize | ||
| pp-trace | ||
| clangd <https://clangd.llvm.org/> | ||
| clang-doc | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // RUN: %check_clang_tidy -std=c11-or-later %s bugprone-sizeof-expression %t | ||
|
|
||
| #define alignof(type_name) _Alignof(type_name) | ||
| extern void sink(const void *P); | ||
|
|
||
| enum { BufferSize = 1024 }; | ||
|
|
||
| struct S { | ||
| long A, B, C; | ||
| }; | ||
|
|
||
| void bad4d(void) { | ||
| struct S Buffer[BufferSize]; | ||
|
|
||
| struct S *P = &Buffer[0]; | ||
| struct S *Q = P; | ||
| while (Q < P + alignof(Buffer)) { | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'alignof(...)' 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(struct S)' == {{[0-9]+}} | ||
| sink(Q++); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,372 @@ | ||
| // 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; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // RUN: %check_clang_tidy -std=c++20 %s modernize-avoid-c-arrays %t | ||
|
|
||
| int f1(int data[], int size) { | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: do not declare C-style arrays, use std::span<> instead | ||
| int f4[] = {1, 2}; | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead | ||
| } | ||
|
|
||
| int f2(int data[100]) { | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: do not declare C-style arrays, use std::array<> instead | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,9 @@ | ||
| // RUN: %check_clang_tidy -std=c++17 %s modernize-avoid-c-arrays %t -- \ | ||
| // RUN: -config='{CheckOptions: { modernize-avoid-c-arrays.AllowStringArrays: true }}' | ||
|
|
||
| const char name[] = "name"; | ||
| const char array[] = {'n', 'a', 'm', 'e', '\0'}; | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays] | ||
|
|
||
| void takeCharArray(const char name[]); | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead [modernize-avoid-c-arrays] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // RUN: %check_clang_tidy -std=c++14-or-later %s performance-unnecessary-value-param %t | ||
|
|
||
| // The test case used to crash clang-tidy. | ||
| // https://github.com/llvm/llvm-project/issues/108963 | ||
|
|
||
| struct A | ||
| { | ||
| template<typename T> A(T&&) {} | ||
| }; | ||
|
|
||
| struct B | ||
| { | ||
| ~B(); | ||
| }; | ||
|
|
||
| struct C | ||
| { | ||
| A a; | ||
| C(B, int i) : a(i) {} | ||
| // CHECK-MESSAGES: [[@LINE-1]]:6: warning: the parameter #1 is copied for each invocation but only used as a const reference; consider making it a const reference | ||
| }; | ||
|
|
||
| C c(B(), 0); |