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 | |
15 | void 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 | |
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(lhs: left->buffer, rhs: right->buffer, count: 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 | |
35 | void 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 | |
44 | struct S2 { |
45 | int i; |
46 | float f; |
47 | }; |
48 | |
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(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 | |
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 | |
67 | void 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 | |
73 | void 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 | |
79 | struct PredeclaredType; |
80 | |
81 | void Test_PredeclaredType(const struct PredeclaredType *lhs, |
82 | const struct PredeclaredType *rhs) { |
83 | memcmp(lhs, rhs, count: 1); // no-warning: predeclared type |
84 | } |
85 | |
86 | struct NoPadding { |
87 | int x; |
88 | int y; |
89 | }; |
90 | |
91 | void Test_NoPadding(void) { |
92 | struct NoPadding a, b; |
93 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct NoPadding)); |
94 | } |
95 | |
96 | void TestArray_NoPadding(void) { |
97 | struct NoPadding a[3], b[3]; |
98 | memcmp(lhs: a, rhs: b, count: 3 * sizeof(struct NoPadding)); |
99 | } |
100 | |
101 | struct TrailingPadding { |
102 | int i; |
103 | char c; |
104 | }; |
105 | |
106 | void 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 | |
115 | struct TrailingPadding2 { |
116 | int i[2]; |
117 | char c; |
118 | }; |
119 | |
120 | void 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 | |
127 | void Test_UnknownCount(size_t count) { |
128 | struct TrailingPadding a, b; |
129 | memcmp(lhs: &a, rhs: &b, count); // no-warning: unknown count value |
130 | } |
131 | |
132 | void 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 | |
138 | void 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 | |
144 | struct InnerPadding { |
145 | char c; |
146 | int i; |
147 | }; |
148 | |
149 | void 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 | |
155 | struct Bitfield_TrailingPaddingBytes { |
156 | int x : 10; |
157 | int y : 6; |
158 | }; |
159 | |
160 | void 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 | |
166 | struct Bitfield_TrailingPaddingBits { |
167 | int x : 10; |
168 | int y : 20; |
169 | }; |
170 | |
171 | void 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 | |
177 | struct Bitfield_InnerPaddingBits { |
178 | char x : 2; |
179 | int : 0; |
180 | char y : 8; |
181 | }; |
182 | |
183 | void 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 | |
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 | |
198 | void 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 | |
203 | struct Bitfield_TrailingUnnamed { |
204 | int i[2]; |
205 | int : 0; |
206 | }; |
207 | |
208 | void 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 | |
214 | struct PaddingAfterUnion { |
215 | union { |
216 | unsigned short a; |
217 | short b; |
218 | } x; |
219 | |
220 | int y; |
221 | }; |
222 | |
223 | void 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 | |
229 | struct Union_NoPadding { |
230 | union { |
231 | int a; |
232 | unsigned int b; |
233 | } x; |
234 | |
235 | int y; |
236 | }; |
237 | |
238 | void 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 | |
244 | union UnionWithPaddingInNestedStruct { |
245 | int i; |
246 | |
247 | struct { |
248 | int i; |
249 | char c; |
250 | } x; |
251 | }; |
252 | |
253 | void 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 | |
259 | struct PaddingInNested { |
260 | struct TrailingPadding x; |
261 | char y; |
262 | }; |
263 | |
264 | void 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 | |
270 | struct PaddingAfterNested { |
271 | struct { |
272 | char a; |
273 | char b; |
274 | } x; |
275 | int y; |
276 | }; |
277 | |
278 | void 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 | |
284 | struct AtomicMember { |
285 | _Atomic(int) x; |
286 | }; |
287 | |
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(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 | |