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