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 
f(C & c1,C & c2)17 void f(C &c1, C &c2) {
18   if (!std::memcmp(&c1, &c2, 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 
test()30 void test() {
31   S a, b;
32   std::memcmp(&a, &b, 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 
testDerived()47 void testDerived() {
48   Derived a, b;
49   std::memcmp(&a, &b, 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(&a, &b, 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 
testDerived2()55 void testDerived2() {
56   Derived2 a, b;
57   std::memcmp(&a, &b, 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(&a, &b, 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 
testDerived()74 void testDerived() {
75   Derived a, b;
76   std::memcmp(&a, &b, sizeof(Base));
77   std::memcmp(&a, &b, sizeof(Derived));
78 }
79 
testDerived2()80 void testDerived2() {
81   Derived2 a, b;
82   std::memcmp(&a, &b, sizeof(char));
83   std::memcmp(&a, &b, sizeof(Base));
84   std::memcmp(&a, &b, 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 
test()97 void test() {
98   C a, b;
99   std::memcmp(&a, &b, 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 
test()111 void test() {
112   S a, b;
113   std::memcmp(&a, &b, sizeof(S));
114 }
115 } // namespace static_ignored
116 
117 namespace operator_void_ptr {
118 struct S {
119   operator void *() const;
120 };
121 
test()122 void test() {
123   S s;
124   std::memcmp(s, s, sizeof(s));
125 }
126 } // namespace operator_void_ptr
127 
128 namespace empty_struct {
129 struct S {};
130 
test()131 void test() {
132   S a, b;
133   std::memcmp(&a, &b, 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 
test()144 void test() {
145   S a, b;
146   std::memcmp(&a, &b, 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 
test()160 void test() {
161   S a, b;
162   std::memcmp(&a, &b, 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 
test()173 void test() {
174   S a, b;
175   std::memcmp(&a, &b, 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 
test()190 void test() {
191   S a, b;
192   std::memcmp(&a, &b, 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 
test()203 void test() {
204   S a, b;
205   std::memcmp(&a, &b, 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>
compare(const T * l,const T * r)212 int compare(const T *l, const T *r) {
213   return std::memcmp(l, r, sizeof(T));
214 }
215 
test()216 void test() {
217   int a, b;
218   compare(&a, &b);
219 }
220 } // namespace no_warning_in_template
221 
222 namespace warning_in_template {
223 template <typename T>
compare(const T * l,const T * r)224 int compare(const T *l, const T *r) {
225   return std::memcmp(l, r, 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 
test()229 void test() {
230   float a, b;
231   compare(&a, &b);
232 }
233 } // namespace warning_in_template
234