// 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(void) {
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(void) {
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(void) {
struct NoPadding a, b;
memcmp(&a, &b, sizeof(struct NoPadding));
}
void TestArray_NoPadding(void) {
struct NoPadding a[3], b[3];
memcmp(a, b, 3 * sizeof(struct NoPadding));
}
struct TrailingPadding {
int i;
char c;
};
void Test_TrailingPadding(void) {
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(void) {
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(void) {
struct TrailingPadding a, b;
memcmp((void *)&a, (void *)&b,
sizeof(struct TrailingPadding)); // no-warning: explicit cast
}
void TestArray_TrailingPadding(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
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(void) {
// 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
}