1// RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \
2// RUN: -- -- -target x86_64-unknown-unknown -std=c99
3
4typedef __SIZE_TYPE__ size_t;
5int memcmp(const void *lhs, const void *rhs, size_t count);
6
7// Examples from cert rule exp42-c
8
9struct S {
10 char c;
11 int i;
12 char buffer[13];
13};
14
15void exp42_c_noncompliant(const struct S *left, const struct S *right) {
16 if ((left && right) && (0 == memcmp(lhs: left, rhs: right, count: 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
21void 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(lhs: left->buffer, rhs: right->buffer, count: 13))) {
24 }
25}
26
27#pragma pack(push, 1)
28struct Packed_S {
29 char c;
30 int i;
31 char buffer[13];
32};
33#pragma pack(pop)
34
35void compliant_packed(const struct Packed_S *left,
36 const struct Packed_S *right) {
37 if ((left && right) && (0 == memcmp(lhs: left, rhs: right, count: sizeof(struct Packed_S)))) {
38 // no-warning
39 }
40}
41
42// Examples from cert rule flp37-c
43
44struct S2 {
45 int i;
46 float f;
47};
48
49int 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(lhs: s1, rhs: s2, count: 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
58int 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
67void Test_Float(void) {
68 float a, b;
69 memcmp(lhs: &a, rhs: &b, count: 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
73void TestArray_Float(void) {
74 float a[3], b[3];
75 memcmp(lhs: a, rhs: b, count: 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
79struct PredeclaredType;
80
81void Test_PredeclaredType(const struct PredeclaredType *lhs,
82 const struct PredeclaredType *rhs) {
83 memcmp(lhs, rhs, count: 1); // no-warning: predeclared type
84}
85
86struct NoPadding {
87 int x;
88 int y;
89};
90
91void Test_NoPadding(void) {
92 struct NoPadding a, b;
93 memcmp(lhs: &a, rhs: &b, count: sizeof(struct NoPadding));
94}
95
96void TestArray_NoPadding(void) {
97 struct NoPadding a[3], b[3];
98 memcmp(lhs: a, rhs: b, count: 3 * sizeof(struct NoPadding));
99}
100
101struct TrailingPadding {
102 int i;
103 char c;
104};
105
106void Test_TrailingPadding(void) {
107 struct TrailingPadding a, b;
108 memcmp(lhs: &a, rhs: &b, count: 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(lhs: &a, rhs: &b, count: sizeof(int)); // no-warning: not comparing entire object
111 memcmp(lhs: &a, rhs: &b, count: 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
115struct TrailingPadding2 {
116 int i[2];
117 char c;
118};
119
120void Test_TrailingPadding2(void) {
121 struct TrailingPadding2 a, b;
122 memcmp(lhs: &a, rhs: &b, count: 2 * sizeof(int)); // no-warning: not comparing entire object
123 memcmp(lhs: &a, rhs: &b, count: 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
127void Test_UnknownCount(size_t count) {
128 struct TrailingPadding a, b;
129 memcmp(lhs: &a, rhs: &b, count); // no-warning: unknown count value
130}
131
132void Test_ExplicitVoidCast(void) {
133 struct TrailingPadding a, b;
134 memcmp(lhs: (void *)&a, rhs: (void *)&b,
135 count: sizeof(struct TrailingPadding)); // no-warning: explicit cast
136}
137
138void TestArray_TrailingPadding(void) {
139 struct TrailingPadding a[3], b[3];
140 memcmp(lhs: a, rhs: b, count: 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
144struct InnerPadding {
145 char c;
146 int i;
147};
148
149void Test_InnerPadding(void) {
150 struct InnerPadding a, b;
151 memcmp(lhs: &a, rhs: &b, count: 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
155struct Bitfield_TrailingPaddingBytes {
156 int x : 10;
157 int y : 6;
158};
159
160void Test_Bitfield_TrailingPaddingBytes(void) {
161 struct Bitfield_TrailingPaddingBytes a, b;
162 memcmp(lhs: &a, rhs: &b, count: 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
166struct Bitfield_TrailingPaddingBits {
167 int x : 10;
168 int y : 20;
169};
170
171void Test_Bitfield_TrailingPaddingBits(void) {
172 struct Bitfield_TrailingPaddingBits a, b;
173 memcmp(lhs: &a, rhs: &b, count: 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
177struct Bitfield_InnerPaddingBits {
178 char x : 2;
179 int : 0;
180 char y : 8;
181};
182
183void Test_Bitfield_InnerPaddingBits(void) {
184 struct Bitfield_InnerPaddingBits a, b;
185 memcmp(lhs: &a, rhs: &b, count: 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
189struct 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
198void Test_Bitfield_NoPadding(void) {
199 struct Bitfield_NoPadding a, b;
200 memcmp(lhs: &a, rhs: &b, count: sizeof(struct Bitfield_NoPadding)); // no-warning
201}
202
203struct Bitfield_TrailingUnnamed {
204 int i[2];
205 int : 0;
206};
207
208void Bitfield_TrailingUnnamed(void) {
209 struct Bitfield_TrailingUnnamed a, b;
210 memcmp(lhs: &a, rhs: &b, count: 2 * sizeof(int)); // no-warning
211 memcmp(lhs: &a, rhs: &b, count: sizeof(struct Bitfield_TrailingUnnamed)); // no-warning
212}
213
214struct PaddingAfterUnion {
215 union {
216 unsigned short a;
217 short b;
218 } x;
219
220 int y;
221};
222
223void Test_PaddingAfterUnion(void) {
224 struct PaddingAfterUnion a, b;
225 memcmp(lhs: &a, rhs: &b, count: 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
229struct Union_NoPadding {
230 union {
231 int a;
232 unsigned int b;
233 } x;
234
235 int y;
236};
237
238void Test_Union_NoPadding(void) {
239 struct Union_NoPadding a, b;
240 memcmp(lhs: &a, rhs: &b, count: 2 * sizeof(int));
241 memcmp(lhs: &a, rhs: &b, count: sizeof(struct Union_NoPadding));
242}
243
244union UnionWithPaddingInNestedStruct {
245 int i;
246
247 struct {
248 int i;
249 char c;
250 } x;
251};
252
253void Test_UnionWithPaddingInNestedStruct(void) {
254 union UnionWithPaddingInNestedStruct a, b;
255 memcmp(lhs: &a, rhs: &b, count: 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
259struct PaddingInNested {
260 struct TrailingPadding x;
261 char y;
262};
263
264void Test_PaddingInNested(void) {
265 struct PaddingInNested a, b;
266 memcmp(lhs: &a, rhs: &b, count: 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
270struct PaddingAfterNested {
271 struct {
272 char a;
273 char b;
274 } x;
275 int y;
276};
277
278void Test_PaddingAfterNested(void) {
279 struct PaddingAfterNested a, b;
280 memcmp(lhs: &a, rhs: &b, count: 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
284struct AtomicMember {
285 _Atomic(int) x;
286};
287
288void 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(lhs: &a, rhs: &b, count: 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

source code of clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-memory-comparison.c