1// RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \
2// RUN: -- -- -target x86_64-unknown-unknown
3
4namespace std {
5typedef __SIZE_TYPE__ size_t;
6int memcmp(const void *lhs, const void *rhs, size_t count);
7} // namespace std
8
9namespace sei_cert_example_oop57_cpp {
10class C {
11 int i;
12
13public:
14 virtual void f();
15};
16
17void 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
24namespace inner_padding_64bit_only {
25struct S {
26 int x;
27 int *y;
28};
29
30void 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
37namespace padding_in_base {
38class Base {
39 char c;
40 int i;
41};
42
43class Derived : public Base {};
44
45class Derived2 : public Derived {};
46
47void 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
55void 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
65namespace no_padding_in_base {
66class Base {
67 int a, b;
68};
69
70class Derived : public Base {};
71
72class Derived2 : public Derived {};
73
74void 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
80void 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
88namespace non_standard_layout {
89class C {
90private:
91 int x;
92
93public:
94 int y;
95};
96
97void 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
105namespace static_ignored {
106struct S {
107 static char c;
108 int i;
109};
110
111void test() {
112 S a, b;
113 std::memcmp(lhs: &a, rhs: &b, count: sizeof(S));
114}
115} // namespace static_ignored
116
117namespace operator_void_ptr {
118struct S {
119 operator void *() const;
120};
121
122void test() {
123 S s;
124 std::memcmp(lhs: s, rhs: s, count: sizeof(s));
125}
126} // namespace operator_void_ptr
127
128namespace empty_struct {
129struct S {};
130
131void 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
138namespace empty_field {
139struct Empty {};
140struct S {
141 Empty e;
142};
143
144void 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
151namespace no_unique_address_attribute {
152struct Empty {};
153
154namespace no_padding {
155struct S {
156 char c;
157 [[no_unique_address]] Empty e;
158};
159
160void test() {
161 S a, b;
162 std::memcmp(lhs: &a, rhs: &b, count: sizeof(S));
163}
164
165} // namespace no_padding
166
167namespace multiple_empties_same_type {
168struct S {
169 char c;
170 [[no_unique_address]] Empty e1, e2;
171};
172
173void 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
181namespace multiple_empties_different_types {
182struct Empty2 {};
183
184struct S {
185 char c;
186 [[no_unique_address]] Empty e1;
187 [[no_unique_address]] Empty2 e2;
188};
189
190void 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
197namespace alignment {
198struct S {
199 char x;
200 alignas(sizeof(int)) char y[sizeof(int)];
201};
202
203void 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
210namespace no_warning_in_template {
211template <typename T>
212int compare(const T *l, const T *r) {
213 return std::memcmp(lhs: l, rhs: r, count: sizeof(T));
214}
215
216void test() {
217 int a, b;
218 compare(l: &a, r: &b);
219}
220} // namespace no_warning_in_template
221
222namespace warning_in_template {
223template <typename T>
224int 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
229void test() {
230 float a, b;
231 compare(l: &a, r: &b);
232}
233} // namespace warning_in_template
234

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