xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-memory-comparison.c (revision 89a1d03e2b379e325daa5249411e414bbd995b5e)
1*89a1d03eSRichard // RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \
2*89a1d03eSRichard // RUN: -- -- -target x86_64-unknown-unknown -std=c99
3*89a1d03eSRichard 
4*89a1d03eSRichard typedef __SIZE_TYPE__ size_t;
5*89a1d03eSRichard int memcmp(const void *lhs, const void *rhs, size_t count);
6*89a1d03eSRichard 
7*89a1d03eSRichard // Examples from cert rule exp42-c
8*89a1d03eSRichard 
9*89a1d03eSRichard struct S {
10*89a1d03eSRichard   char c;
11*89a1d03eSRichard   int i;
12*89a1d03eSRichard   char buffer[13];
13*89a1d03eSRichard };
14*89a1d03eSRichard 
exp42_c_noncompliant(const struct S * left,const struct S * right)15*89a1d03eSRichard void exp42_c_noncompliant(const struct S *left, const struct S *right) {
16*89a1d03eSRichard   if ((left && right) && (0 == memcmp(left, right, sizeof(struct S)))) {
17*89a1d03eSRichard     // 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
18*89a1d03eSRichard   }
19*89a1d03eSRichard }
20*89a1d03eSRichard 
exp42_c_compliant(const struct S * left,const struct S * right)21*89a1d03eSRichard void exp42_c_compliant(const struct S *left, const struct S *right) {
22*89a1d03eSRichard   if ((left && right) && (left->c == right->c) && (left->i == right->i) &&
23*89a1d03eSRichard       (0 == memcmp(left->buffer, right->buffer, 13))) {
24*89a1d03eSRichard   }
25*89a1d03eSRichard }
26*89a1d03eSRichard 
27*89a1d03eSRichard #pragma pack(push, 1)
28*89a1d03eSRichard struct Packed_S {
29*89a1d03eSRichard   char c;
30*89a1d03eSRichard   int i;
31*89a1d03eSRichard   char buffer[13];
32*89a1d03eSRichard };
33*89a1d03eSRichard #pragma pack(pop)
34*89a1d03eSRichard 
compliant_packed(const struct Packed_S * left,const struct Packed_S * right)35*89a1d03eSRichard void compliant_packed(const struct Packed_S *left,
36*89a1d03eSRichard                       const struct Packed_S *right) {
37*89a1d03eSRichard   if ((left && right) && (0 == memcmp(left, right, sizeof(struct Packed_S)))) {
38*89a1d03eSRichard     // no-warning
39*89a1d03eSRichard   }
40*89a1d03eSRichard }
41*89a1d03eSRichard 
42*89a1d03eSRichard // Examples from cert rule flp37-c
43*89a1d03eSRichard 
44*89a1d03eSRichard struct S2 {
45*89a1d03eSRichard   int i;
46*89a1d03eSRichard   float f;
47*89a1d03eSRichard };
48*89a1d03eSRichard 
flp37_c_noncompliant(const struct S2 * s1,const struct S2 * s2)49*89a1d03eSRichard int flp37_c_noncompliant(const struct S2 *s1, const struct S2 *s2) {
50*89a1d03eSRichard   if (!s1 && !s2)
51*89a1d03eSRichard     return 1;
52*89a1d03eSRichard   else if (!s1 || !s2)
53*89a1d03eSRichard     return 0;
54*89a1d03eSRichard   return 0 == memcmp(s1, s2, sizeof(struct S2));
55*89a1d03eSRichard   // 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
56*89a1d03eSRichard }
57*89a1d03eSRichard 
flp37_c_compliant(const struct S2 * s1,const struct S2 * s2)58*89a1d03eSRichard int flp37_c_compliant(const struct S2 *s1, const struct S2 *s2) {
59*89a1d03eSRichard   if (!s1 && !s2)
60*89a1d03eSRichard     return 1;
61*89a1d03eSRichard   else if (!s1 || !s2)
62*89a1d03eSRichard     return 0;
63*89a1d03eSRichard   return s1->i == s2->i && s1->f == s2->f;
64*89a1d03eSRichard   // no-warning
65*89a1d03eSRichard }
66*89a1d03eSRichard 
Test_Float(void)67*89a1d03eSRichard void Test_Float(void) {
68*89a1d03eSRichard   float a, b;
69*89a1d03eSRichard   memcmp(&a, &b, sizeof(float));
70*89a1d03eSRichard   // 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
71*89a1d03eSRichard }
72*89a1d03eSRichard 
TestArray_Float(void)73*89a1d03eSRichard void TestArray_Float(void) {
74*89a1d03eSRichard   float a[3], b[3];
75*89a1d03eSRichard   memcmp(a, b, sizeof(a));
76*89a1d03eSRichard   // 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
77*89a1d03eSRichard }
78*89a1d03eSRichard 
79*89a1d03eSRichard struct PredeclaredType;
80*89a1d03eSRichard 
Test_PredeclaredType(const struct PredeclaredType * lhs,const struct PredeclaredType * rhs)81*89a1d03eSRichard void Test_PredeclaredType(const struct PredeclaredType *lhs,
82*89a1d03eSRichard                           const struct PredeclaredType *rhs) {
83*89a1d03eSRichard   memcmp(lhs, rhs, 1); // no-warning: predeclared type
84*89a1d03eSRichard }
85*89a1d03eSRichard 
86*89a1d03eSRichard struct NoPadding {
87*89a1d03eSRichard   int x;
88*89a1d03eSRichard   int y;
89*89a1d03eSRichard };
90*89a1d03eSRichard 
Test_NoPadding(void)91*89a1d03eSRichard void Test_NoPadding(void) {
92*89a1d03eSRichard   struct NoPadding a, b;
93*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct NoPadding));
94*89a1d03eSRichard }
95*89a1d03eSRichard 
TestArray_NoPadding(void)96*89a1d03eSRichard void TestArray_NoPadding(void) {
97*89a1d03eSRichard   struct NoPadding a[3], b[3];
98*89a1d03eSRichard   memcmp(a, b, 3 * sizeof(struct NoPadding));
99*89a1d03eSRichard }
100*89a1d03eSRichard 
101*89a1d03eSRichard struct TrailingPadding {
102*89a1d03eSRichard   int i;
103*89a1d03eSRichard   char c;
104*89a1d03eSRichard };
105*89a1d03eSRichard 
Test_TrailingPadding(void)106*89a1d03eSRichard void Test_TrailingPadding(void) {
107*89a1d03eSRichard   struct TrailingPadding a, b;
108*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct TrailingPadding));
109*89a1d03eSRichard   // 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
110*89a1d03eSRichard   memcmp(&a, &b, sizeof(int)); // no-warning: not comparing entire object
111*89a1d03eSRichard   memcmp(&a, &b, 2 * sizeof(int));
112*89a1d03eSRichard   // 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
113*89a1d03eSRichard }
114*89a1d03eSRichard 
115*89a1d03eSRichard struct TrailingPadding2 {
116*89a1d03eSRichard   int i[2];
117*89a1d03eSRichard   char c;
118*89a1d03eSRichard };
119*89a1d03eSRichard 
Test_TrailingPadding2(void)120*89a1d03eSRichard void Test_TrailingPadding2(void) {
121*89a1d03eSRichard   struct TrailingPadding2 a, b;
122*89a1d03eSRichard   memcmp(&a, &b, 2 * sizeof(int)); // no-warning: not comparing entire object
123*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct TrailingPadding2));
124*89a1d03eSRichard   // 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
125*89a1d03eSRichard }
126*89a1d03eSRichard 
Test_UnknownCount(size_t count)127*89a1d03eSRichard void Test_UnknownCount(size_t count) {
128*89a1d03eSRichard   struct TrailingPadding a, b;
129*89a1d03eSRichard   memcmp(&a, &b, count); // no-warning: unknown count value
130*89a1d03eSRichard }
131*89a1d03eSRichard 
Test_ExplicitVoidCast(void)132*89a1d03eSRichard void Test_ExplicitVoidCast(void) {
133*89a1d03eSRichard   struct TrailingPadding a, b;
134*89a1d03eSRichard   memcmp((void *)&a, (void *)&b,
135*89a1d03eSRichard          sizeof(struct TrailingPadding)); // no-warning: explicit cast
136*89a1d03eSRichard }
137*89a1d03eSRichard 
TestArray_TrailingPadding(void)138*89a1d03eSRichard void TestArray_TrailingPadding(void) {
139*89a1d03eSRichard   struct TrailingPadding a[3], b[3];
140*89a1d03eSRichard   memcmp(a, b, 3 * sizeof(struct TrailingPadding));
141*89a1d03eSRichard   // 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
142*89a1d03eSRichard }
143*89a1d03eSRichard 
144*89a1d03eSRichard struct InnerPadding {
145*89a1d03eSRichard   char c;
146*89a1d03eSRichard   int i;
147*89a1d03eSRichard };
148*89a1d03eSRichard 
Test_InnerPadding(void)149*89a1d03eSRichard void Test_InnerPadding(void) {
150*89a1d03eSRichard   struct InnerPadding a, b;
151*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct InnerPadding));
152*89a1d03eSRichard   // 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
153*89a1d03eSRichard }
154*89a1d03eSRichard 
155*89a1d03eSRichard struct Bitfield_TrailingPaddingBytes {
156*89a1d03eSRichard   int x : 10;
157*89a1d03eSRichard   int y : 6;
158*89a1d03eSRichard };
159*89a1d03eSRichard 
Test_Bitfield_TrailingPaddingBytes(void)160*89a1d03eSRichard void Test_Bitfield_TrailingPaddingBytes(void) {
161*89a1d03eSRichard   struct Bitfield_TrailingPaddingBytes a, b;
162*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct S));
163*89a1d03eSRichard   // 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
164*89a1d03eSRichard }
165*89a1d03eSRichard 
166*89a1d03eSRichard struct Bitfield_TrailingPaddingBits {
167*89a1d03eSRichard   int x : 10;
168*89a1d03eSRichard   int y : 20;
169*89a1d03eSRichard };
170*89a1d03eSRichard 
Test_Bitfield_TrailingPaddingBits(void)171*89a1d03eSRichard void Test_Bitfield_TrailingPaddingBits(void) {
172*89a1d03eSRichard   struct Bitfield_TrailingPaddingBits a, b;
173*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct Bitfield_TrailingPaddingBits));
174*89a1d03eSRichard   // 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
175*89a1d03eSRichard }
176*89a1d03eSRichard 
177*89a1d03eSRichard struct Bitfield_InnerPaddingBits {
178*89a1d03eSRichard   char x : 2;
179*89a1d03eSRichard   int : 0;
180*89a1d03eSRichard   char y : 8;
181*89a1d03eSRichard };
182*89a1d03eSRichard 
Test_Bitfield_InnerPaddingBits(void)183*89a1d03eSRichard void Test_Bitfield_InnerPaddingBits(void) {
184*89a1d03eSRichard   struct Bitfield_InnerPaddingBits a, b;
185*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct Bitfield_InnerPaddingBits));
186*89a1d03eSRichard   // 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
187*89a1d03eSRichard }
188*89a1d03eSRichard 
189*89a1d03eSRichard struct Bitfield_NoPadding {
190*89a1d03eSRichard   int i : 10;
191*89a1d03eSRichard   int j : 10;
192*89a1d03eSRichard   int k : 10;
193*89a1d03eSRichard   int l : 2;
194*89a1d03eSRichard };
195*89a1d03eSRichard _Static_assert(sizeof(struct Bitfield_NoPadding) == sizeof(int),
196*89a1d03eSRichard                "Bit-fields should line up perfectly");
197*89a1d03eSRichard 
Test_Bitfield_NoPadding(void)198*89a1d03eSRichard void Test_Bitfield_NoPadding(void) {
199*89a1d03eSRichard   struct Bitfield_NoPadding a, b;
200*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct Bitfield_NoPadding)); // no-warning
201*89a1d03eSRichard }
202*89a1d03eSRichard 
203*89a1d03eSRichard struct Bitfield_TrailingUnnamed {
204*89a1d03eSRichard   int i[2];
205*89a1d03eSRichard   int : 0;
206*89a1d03eSRichard };
207*89a1d03eSRichard 
Bitfield_TrailingUnnamed(void)208*89a1d03eSRichard void Bitfield_TrailingUnnamed(void) {
209*89a1d03eSRichard   struct Bitfield_TrailingUnnamed a, b;
210*89a1d03eSRichard   memcmp(&a, &b, 2 * sizeof(int));                         // no-warning
211*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct Bitfield_TrailingUnnamed)); // no-warning
212*89a1d03eSRichard }
213*89a1d03eSRichard 
214*89a1d03eSRichard struct PaddingAfterUnion {
215*89a1d03eSRichard   union {
216*89a1d03eSRichard     unsigned short a;
217*89a1d03eSRichard     short b;
218*89a1d03eSRichard   } x;
219*89a1d03eSRichard 
220*89a1d03eSRichard   int y;
221*89a1d03eSRichard };
222*89a1d03eSRichard 
Test_PaddingAfterUnion(void)223*89a1d03eSRichard void Test_PaddingAfterUnion(void) {
224*89a1d03eSRichard   struct PaddingAfterUnion a, b;
225*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct PaddingAfterUnion));
226*89a1d03eSRichard   // 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
227*89a1d03eSRichard }
228*89a1d03eSRichard 
229*89a1d03eSRichard struct Union_NoPadding {
230*89a1d03eSRichard   union {
231*89a1d03eSRichard     int a;
232*89a1d03eSRichard     unsigned int b;
233*89a1d03eSRichard   } x;
234*89a1d03eSRichard 
235*89a1d03eSRichard   int y;
236*89a1d03eSRichard };
237*89a1d03eSRichard 
Test_Union_NoPadding(void)238*89a1d03eSRichard void Test_Union_NoPadding(void) {
239*89a1d03eSRichard   struct Union_NoPadding a, b;
240*89a1d03eSRichard   memcmp(&a, &b, 2 * sizeof(int));
241*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct Union_NoPadding));
242*89a1d03eSRichard }
243*89a1d03eSRichard 
244*89a1d03eSRichard union UnionWithPaddingInNestedStruct {
245*89a1d03eSRichard   int i;
246*89a1d03eSRichard 
247*89a1d03eSRichard   struct {
248*89a1d03eSRichard     int i;
249*89a1d03eSRichard     char c;
250*89a1d03eSRichard   } x;
251*89a1d03eSRichard };
252*89a1d03eSRichard 
Test_UnionWithPaddingInNestedStruct(void)253*89a1d03eSRichard void Test_UnionWithPaddingInNestedStruct(void) {
254*89a1d03eSRichard   union UnionWithPaddingInNestedStruct a, b;
255*89a1d03eSRichard   memcmp(&a, &b, sizeof(union UnionWithPaddingInNestedStruct));
256*89a1d03eSRichard   // 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
257*89a1d03eSRichard }
258*89a1d03eSRichard 
259*89a1d03eSRichard struct PaddingInNested {
260*89a1d03eSRichard   struct TrailingPadding x;
261*89a1d03eSRichard   char y;
262*89a1d03eSRichard };
263*89a1d03eSRichard 
Test_PaddingInNested(void)264*89a1d03eSRichard void Test_PaddingInNested(void) {
265*89a1d03eSRichard   struct PaddingInNested a, b;
266*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct PaddingInNested));
267*89a1d03eSRichard   // 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
268*89a1d03eSRichard }
269*89a1d03eSRichard 
270*89a1d03eSRichard struct PaddingAfterNested {
271*89a1d03eSRichard   struct {
272*89a1d03eSRichard     char a;
273*89a1d03eSRichard     char b;
274*89a1d03eSRichard   } x;
275*89a1d03eSRichard   int y;
276*89a1d03eSRichard };
277*89a1d03eSRichard 
Test_PaddingAfterNested(void)278*89a1d03eSRichard void Test_PaddingAfterNested(void) {
279*89a1d03eSRichard   struct PaddingAfterNested a, b;
280*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct PaddingAfterNested));
281*89a1d03eSRichard   // 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
282*89a1d03eSRichard }
283*89a1d03eSRichard 
284*89a1d03eSRichard struct AtomicMember {
285*89a1d03eSRichard   _Atomic(int) x;
286*89a1d03eSRichard };
287*89a1d03eSRichard 
Test_AtomicMember(void)288*89a1d03eSRichard void Test_AtomicMember(void) {
289*89a1d03eSRichard   // FIXME: this is a false positive as the list of objects with unique object
290*89a1d03eSRichard   // representations is incomplete.
291*89a1d03eSRichard   struct AtomicMember a, b;
292*89a1d03eSRichard   memcmp(&a, &b, sizeof(struct AtomicMember));
293*89a1d03eSRichard   // 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
294*89a1d03eSRichard }
295