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