1 | // RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \ |
2 | // RUN: -- -- -target x86_64-unknown-unknown |
3 | |
4 | namespace std { |
5 | typedef __SIZE_TYPE__ size_t; |
6 | int memcmp(const void *lhs, const void *rhs, size_t count); |
7 | } // namespace std |
8 | |
9 | namespace sei_cert_example_oop57_cpp { |
10 | class C { |
11 | int i; |
12 | |
13 | public: |
14 | virtual void f(); |
15 | }; |
16 | |
17 | void f(C &c1, C &c2) { |
18 | if (!std::memcmp(lhs: &c1, rhs: &c2, count: sizeof(C))) { |
19 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: comparing object representation of non-standard-layout type 'C'; consider using a comparison operator instead |
20 | } |
21 | } |
22 | } // namespace sei_cert_example_oop57_cpp |
23 | |
24 | namespace inner_padding_64bit_only { |
25 | struct S { |
26 | int x; |
27 | int *y; |
28 | }; |
29 | |
30 | void test() { |
31 | S a, b; |
32 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
33 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'S' which does not have a unique object representation; consider comparing the members of the object manually |
34 | } |
35 | } // namespace inner_padding_64bit_only |
36 | |
37 | namespace padding_in_base { |
38 | class Base { |
39 | char c; |
40 | int i; |
41 | }; |
42 | |
43 | class Derived : public Base {}; |
44 | |
45 | class Derived2 : public Derived {}; |
46 | |
47 | void testDerived() { |
48 | Derived a, b; |
49 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Base)); |
50 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'Derived' which does not have a unique object representation; consider comparing the members of the object manually |
51 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Derived)); |
52 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'Derived' which does not have a unique object representation; consider comparing the members of the object manually |
53 | } |
54 | |
55 | void testDerived2() { |
56 | Derived2 a, b; |
57 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Base)); |
58 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'Derived2' which does not have a unique object representation; consider comparing the members of the object manually |
59 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Derived2)); |
60 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'Derived2' which does not have a unique object representation; consider comparing the members of the object manually |
61 | } |
62 | |
63 | } // namespace padding_in_base |
64 | |
65 | namespace no_padding_in_base { |
66 | class Base { |
67 | int a, b; |
68 | }; |
69 | |
70 | class Derived : public Base {}; |
71 | |
72 | class Derived2 : public Derived {}; |
73 | |
74 | void testDerived() { |
75 | Derived a, b; |
76 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Base)); |
77 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Derived)); |
78 | } |
79 | |
80 | void testDerived2() { |
81 | Derived2 a, b; |
82 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(char)); |
83 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Base)); |
84 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(Derived2)); |
85 | } |
86 | } // namespace no_padding_in_base |
87 | |
88 | namespace non_standard_layout { |
89 | class C { |
90 | private: |
91 | int x; |
92 | |
93 | public: |
94 | int y; |
95 | }; |
96 | |
97 | void test() { |
98 | C a, b; |
99 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(C)); |
100 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of non-standard-layout type 'C'; consider using a comparison operator instead |
101 | } |
102 | |
103 | } // namespace non_standard_layout |
104 | |
105 | namespace static_ignored { |
106 | struct S { |
107 | static char c; |
108 | int i; |
109 | }; |
110 | |
111 | void test() { |
112 | S a, b; |
113 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
114 | } |
115 | } // namespace static_ignored |
116 | |
117 | namespace operator_void_ptr { |
118 | struct S { |
119 | operator void *() const; |
120 | }; |
121 | |
122 | void test() { |
123 | S s; |
124 | std::memcmp(lhs: s, rhs: s, count: sizeof(s)); |
125 | } |
126 | } // namespace operator_void_ptr |
127 | |
128 | namespace empty_struct { |
129 | struct S {}; |
130 | |
131 | void test() { |
132 | S a, b; |
133 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
134 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'S' which does not have a unique object representation; consider comparing the members of the object manually |
135 | } |
136 | } // namespace empty_struct |
137 | |
138 | namespace empty_field { |
139 | struct Empty {}; |
140 | struct S { |
141 | Empty e; |
142 | }; |
143 | |
144 | void test() { |
145 | S a, b; |
146 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
147 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'S' which does not have a unique object representation; consider comparing the members of the object manually |
148 | } |
149 | } // namespace empty_field |
150 | |
151 | namespace no_unique_address_attribute { |
152 | struct Empty {}; |
153 | |
154 | namespace no_padding { |
155 | struct S { |
156 | char c; |
157 | [[no_unique_address]] Empty e; |
158 | }; |
159 | |
160 | void test() { |
161 | S a, b; |
162 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
163 | } |
164 | |
165 | } // namespace no_padding |
166 | |
167 | namespace multiple_empties_same_type { |
168 | struct S { |
169 | char c; |
170 | [[no_unique_address]] Empty e1, e2; |
171 | }; |
172 | |
173 | void test() { |
174 | S a, b; |
175 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
176 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'S' which does not have a unique object representation; consider comparing the members of the object manually |
177 | } |
178 | |
179 | } // namespace multiple_empties_same_type |
180 | |
181 | namespace multiple_empties_different_types { |
182 | struct Empty2 {}; |
183 | |
184 | struct S { |
185 | char c; |
186 | [[no_unique_address]] Empty e1; |
187 | [[no_unique_address]] Empty2 e2; |
188 | }; |
189 | |
190 | void test() { |
191 | S a, b; |
192 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
193 | } |
194 | } // namespace multiple_empties_different_types |
195 | } // namespace no_unique_address_attribute |
196 | |
197 | namespace alignment { |
198 | struct S { |
199 | char x; |
200 | alignas(sizeof(int)) char y[sizeof(int)]; |
201 | }; |
202 | |
203 | void test() { |
204 | S a, b; |
205 | std::memcmp(lhs: &a, rhs: &b, count: sizeof(S)); |
206 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'S' which does not have a unique object representation; consider comparing the members of the object manually |
207 | } |
208 | } // namespace alignment |
209 | |
210 | namespace no_warning_in_template { |
211 | template <typename T> |
212 | int compare(const T *l, const T *r) { |
213 | return std::memcmp(lhs: l, rhs: r, count: sizeof(T)); |
214 | } |
215 | |
216 | void test() { |
217 | int a, b; |
218 | compare(l: &a, r: &b); |
219 | } |
220 | } // namespace no_warning_in_template |
221 | |
222 | namespace warning_in_template { |
223 | template <typename T> |
224 | int compare(const T *l, const T *r) { |
225 | return std::memcmp(lhs: l, rhs: r, count: sizeof(T)); |
226 | // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually |
227 | } |
228 | |
229 | void test() { |
230 | float a, b; |
231 | compare(l: &a, r: &b); |
232 | } |
233 | } // namespace warning_in_template |
234 | |