| // RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \ |
| // RUN: -- -- -target x86_64-unknown-unknown -std=c99 |
| |
| typedef __SIZE_TYPE__ size_t; |
| int memcmp(const void *lhs, const void *rhs, size_t count); |
| |
| // Examples from cert rule exp42-c |
| |
| struct S { |
| char c; |
| int i; |
| char buffer[13]; |
| }; |
| |
| void exp42_c_noncompliant(const struct S *left, const struct S *right) { |
| if ((left && right) && (0 == memcmp(left, right, sizeof(struct S)))) { |
| // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: comparing object representation of type 'struct S' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| } |
| |
| void exp42_c_compliant(const struct S *left, const struct S *right) { |
| if ((left && right) && (left->c == right->c) && (left->i == right->i) && |
| (0 == memcmp(left->buffer, right->buffer, 13))) { |
| } |
| } |
| |
| #pragma pack(push, 1) |
| struct Packed_S { |
| char c; |
| int i; |
| char buffer[13]; |
| }; |
| #pragma pack(pop) |
| |
| void compliant_packed(const struct Packed_S *left, |
| const struct Packed_S *right) { |
| if ((left && right) && (0 == memcmp(left, right, sizeof(struct Packed_S)))) { |
| // no-warning |
| } |
| } |
| |
| // Examples from cert rule flp37-c |
| |
| struct S2 { |
| int i; |
| float f; |
| }; |
| |
| int flp37_c_noncompliant(const struct S2 *s1, const struct S2 *s2) { |
| if (!s1 && !s2) |
| return 1; |
| else if (!s1 || !s2) |
| return 0; |
| return 0 == memcmp(s1, s2, sizeof(struct S2)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: comparing object representation of type 'struct S2' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| int flp37_c_compliant(const struct S2 *s1, const struct S2 *s2) { |
| if (!s1 && !s2) |
| return 1; |
| else if (!s1 || !s2) |
| return 0; |
| return s1->i == s2->i && s1->f == s2->f; |
| // no-warning |
| } |
| |
| void Test_Float() { |
| float a, b; |
| memcmp(&a, &b, sizeof(float)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually |
| } |
| |
| void TestArray_Float() { |
| float a[3], b[3]; |
| memcmp(a, b, sizeof(a)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually |
| } |
| |
| struct PredeclaredType; |
| |
| void Test_PredeclaredType(const struct PredeclaredType *lhs, |
| const struct PredeclaredType *rhs) { |
| memcmp(lhs, rhs, 1); // no-warning: predeclared type |
| } |
| |
| struct NoPadding { |
| int x; |
| int y; |
| }; |
| |
| void Test_NoPadding() { |
| struct NoPadding a, b; |
| memcmp(&a, &b, sizeof(struct NoPadding)); |
| } |
| |
| void TestArray_NoPadding() { |
| struct NoPadding a[3], b[3]; |
| memcmp(a, b, 3 * sizeof(struct NoPadding)); |
| } |
| |
| struct TrailingPadding { |
| int i; |
| char c; |
| }; |
| |
| void Test_TrailingPadding() { |
| struct TrailingPadding a, b; |
| memcmp(&a, &b, sizeof(struct TrailingPadding)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| memcmp(&a, &b, sizeof(int)); // no-warning: not comparing entire object |
| memcmp(&a, &b, 2 * sizeof(int)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct TrailingPadding2 { |
| int i[2]; |
| char c; |
| }; |
| |
| void Test_TrailingPadding2() { |
| struct TrailingPadding2 a, b; |
| memcmp(&a, &b, 2 * sizeof(int)); // no-warning: not comparing entire object |
| memcmp(&a, &b, sizeof(struct TrailingPadding2)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding2' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| void Test_UnknownCount(size_t count) { |
| struct TrailingPadding a, b; |
| memcmp(&a, &b, count); // no-warning: unknown count value |
| } |
| |
| void Test_ExplicitVoidCast() { |
| struct TrailingPadding a, b; |
| memcmp((void *)&a, (void *)&b, |
| sizeof(struct TrailingPadding)); // no-warning: explicit cast |
| } |
| |
| void TestArray_TrailingPadding() { |
| struct TrailingPadding a[3], b[3]; |
| memcmp(a, b, 3 * sizeof(struct TrailingPadding)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct InnerPadding { |
| char c; |
| int i; |
| }; |
| |
| void Test_InnerPadding() { |
| struct InnerPadding a, b; |
| memcmp(&a, &b, sizeof(struct InnerPadding)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct InnerPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct Bitfield_TrailingPaddingBytes { |
| int x : 10; |
| int y : 6; |
| }; |
| |
| void Test_Bitfield_TrailingPaddingBytes() { |
| struct Bitfield_TrailingPaddingBytes a, b; |
| memcmp(&a, &b, sizeof(struct S)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_TrailingPaddingBytes' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct Bitfield_TrailingPaddingBits { |
| int x : 10; |
| int y : 20; |
| }; |
| |
| void Test_Bitfield_TrailingPaddingBits() { |
| struct Bitfield_TrailingPaddingBits a, b; |
| memcmp(&a, &b, sizeof(struct Bitfield_TrailingPaddingBits)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_TrailingPaddingBits' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct Bitfield_InnerPaddingBits { |
| char x : 2; |
| int : 0; |
| char y : 8; |
| }; |
| |
| void Test_Bitfield_InnerPaddingBits() { |
| struct Bitfield_InnerPaddingBits a, b; |
| memcmp(&a, &b, sizeof(struct Bitfield_InnerPaddingBits)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_InnerPaddingBits' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct Bitfield_NoPadding { |
| int i : 10; |
| int j : 10; |
| int k : 10; |
| int l : 2; |
| }; |
| _Static_assert(sizeof(struct Bitfield_NoPadding) == sizeof(int), |
| "Bit-fields should line up perfectly"); |
| |
| void Test_Bitfield_NoPadding() { |
| struct Bitfield_NoPadding a, b; |
| memcmp(&a, &b, sizeof(struct Bitfield_NoPadding)); // no-warning |
| } |
| |
| struct Bitfield_TrailingUnnamed { |
| int i[2]; |
| int : 0; |
| }; |
| |
| void Bitfield_TrailingUnnamed() { |
| struct Bitfield_TrailingUnnamed a, b; |
| memcmp(&a, &b, 2 * sizeof(int)); // no-warning |
| memcmp(&a, &b, sizeof(struct Bitfield_TrailingUnnamed)); // no-warning |
| } |
| |
| struct PaddingAfterUnion { |
| union { |
| unsigned short a; |
| short b; |
| } x; |
| |
| int y; |
| }; |
| |
| void Test_PaddingAfterUnion() { |
| struct PaddingAfterUnion a, b; |
| memcmp(&a, &b, sizeof(struct PaddingAfterUnion)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingAfterUnion' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct Union_NoPadding { |
| union { |
| int a; |
| unsigned int b; |
| } x; |
| |
| int y; |
| }; |
| |
| void Test_Union_NoPadding() { |
| struct Union_NoPadding a, b; |
| memcmp(&a, &b, 2 * sizeof(int)); |
| memcmp(&a, &b, sizeof(struct Union_NoPadding)); |
| } |
| |
| union UnionWithPaddingInNestedStruct { |
| int i; |
| |
| struct { |
| int i; |
| char c; |
| } x; |
| }; |
| |
| void Test_UnionWithPaddingInNestedStruct() { |
| union UnionWithPaddingInNestedStruct a, b; |
| memcmp(&a, &b, sizeof(union UnionWithPaddingInNestedStruct)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'union UnionWithPaddingInNestedStruct' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct PaddingInNested { |
| struct TrailingPadding x; |
| char y; |
| }; |
| |
| void Test_PaddingInNested() { |
| struct PaddingInNested a, b; |
| memcmp(&a, &b, sizeof(struct PaddingInNested)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingInNested' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct PaddingAfterNested { |
| struct { |
| char a; |
| char b; |
| } x; |
| int y; |
| }; |
| |
| void Test_PaddingAfterNested() { |
| struct PaddingAfterNested a, b; |
| memcmp(&a, &b, sizeof(struct PaddingAfterNested)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingAfterNested' which does not have a unique object representation; consider comparing the members of the object manually |
| } |
| |
| struct AtomicMember { |
| _Atomic(int) x; |
| }; |
| |
| void Test_AtomicMember() { |
| // FIXME: this is a false positive as the list of objects with unique object |
| // representations is incomplete. |
| struct AtomicMember a, b; |
| memcmp(&a, &b, sizeof(struct AtomicMember)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct AtomicMember' which does not have a unique object representation; consider comparing the members of the object manually |
| } |