1 | // RUN: %check_clang_tidy %s bugprone-undefined-memory-manipulation %t |
2 | |
3 | void *memset(void *, int, __SIZE_TYPE__); |
4 | void *memcpy(void *, const void *, __SIZE_TYPE__); |
5 | void *memmove(void *, const void *, __SIZE_TYPE__); |
6 | |
7 | namespace std { |
8 | using ::memcpy; |
9 | using ::memmove; |
10 | using ::memset; |
11 | } |
12 | |
13 | namespace types { |
14 | // TriviallyCopyable types: |
15 | struct Plain { |
16 | int n; |
17 | }; |
18 | |
19 | enum E { |
20 | X, |
21 | Y, |
22 | Z |
23 | }; |
24 | |
25 | struct Base { |
26 | float b; |
27 | }; |
28 | |
29 | struct Derived : Base { |
30 | bool d; |
31 | }; |
32 | |
33 | // not TriviallyCopyable types: |
34 | struct Destruct { |
35 | ~Destruct() {} |
36 | }; |
37 | |
38 | struct Copy { |
39 | Copy() {} |
40 | Copy(const Copy &) {} |
41 | }; |
42 | |
43 | struct Move { |
44 | Move() {} |
45 | Move(Move &&) {} |
46 | }; |
47 | |
48 | struct VirtualFunc { |
49 | virtual void f() {} |
50 | }; |
51 | |
52 | struct VirtualBase : virtual Base { |
53 | int vb; |
54 | }; |
55 | |
56 | // Incomplete type, assume it is TriviallyCopyable. |
57 | struct NoDef; |
58 | |
59 | } // end namespace types |
60 | |
61 | void f(types::NoDef *s) { |
62 | memset(s, 0, 5); |
63 | } |
64 | |
65 | template <typename T> |
66 | void memset_temp(T *b) { |
67 | memset(b, 0, sizeof(T)); |
68 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' is not TriviallyCopyable [bugprone-undefined-memory-manipulation] |
69 | } |
70 | |
71 | template <typename S, typename T> |
72 | void memcpy_temp(S *a, T *b) { |
73 | memcpy(a, b, sizeof(T)); |
74 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc' |
75 | } |
76 | |
77 | template <typename S, typename T> |
78 | void memmove_temp(S *a, T *b) { |
79 | memmove(a, b, sizeof(T)); |
80 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc' |
81 | } |
82 | |
83 | namespace aliases { |
84 | using Copy2 = types::Copy; |
85 | typedef types::Move Move2; |
86 | } |
87 | |
88 | void notTriviallyCopyable() { |
89 | types::Plain p; // TriviallyCopyable for variety |
90 | types::Destruct d; |
91 | types::Copy c; |
92 | types::Move m; |
93 | types::VirtualFunc vf; |
94 | types::VirtualBase vb; |
95 | |
96 | memset(&vf, 0, sizeof(int)); |
97 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' |
98 | memset(&d, 0, sizeof(int)); |
99 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct' |
100 | memset(&c, 0, sizeof(int)); |
101 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy' |
102 | std::memset(&m, 0, sizeof(int)); |
103 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move' |
104 | ::memset(&vb, 0, sizeof(int)); |
105 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase' |
106 | |
107 | memcpy(&p, &vf, sizeof(int)); |
108 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc' |
109 | memcpy(&p, &d, sizeof(int)); |
110 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Destruct' |
111 | memcpy(&c, &p, sizeof(int)); |
112 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy' |
113 | std::memcpy(&m, &p, sizeof(int)); |
114 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move' |
115 | ::memcpy(&vb, &p, sizeof(int)); |
116 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase' |
117 | |
118 | memmove(&vf, &p, sizeof(int)); |
119 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' |
120 | memmove(&d, &p, sizeof(int)); |
121 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct' |
122 | memmove(&p, &c, sizeof(int)); |
123 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy' |
124 | std::memmove(&p, &m, sizeof(int)); |
125 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Move' |
126 | ::memmove(&p, &vb, sizeof(int)); |
127 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualBase' |
128 | |
129 | types::Copy ca[10]; |
130 | memset(ca, 0, sizeof(ca)); |
131 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]' |
132 | memset(&ca, 0, sizeof(ca)); |
133 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]' |
134 | |
135 | #define MEMSET memset(&vf, 0, sizeof(int)); |
136 | MEMSET |
137 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' |
138 | #define MEMCPY memcpy(&d, &p, sizeof(int)); |
139 | MEMCPY |
140 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct' |
141 | #define MEMMOVE memmove(&p, &c, sizeof(int)); |
142 | MEMMOVE |
143 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy' |
144 | |
145 | memset_temp<types::VirtualFunc>(b: &vf); |
146 | memcpy_temp<types::Plain, types::VirtualFunc>(a: &p, b: &vf); |
147 | memmove_temp<types::Plain, types::VirtualFunc>(a: &p, b: &vf); |
148 | |
149 | aliases::Copy2 c2; |
150 | aliases::Move2 m2; |
151 | memset(&c2, 0, sizeof(int)); |
152 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2' |
153 | memset(&m2, 0, sizeof(int)); |
154 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Move2' |
155 | |
156 | typedef aliases::Copy2 Copy3; |
157 | typedef aliases::Copy2 *PCopy2; |
158 | typedef Copy3 *PCopy3; |
159 | Copy3 c3; |
160 | PCopy2 pc2; |
161 | PCopy3 pc3; |
162 | memset(&c3, 0, sizeof(int)); |
163 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3' |
164 | memset(pc2, 0, sizeof(int)); |
165 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2' |
166 | memset(pc3, 0, sizeof(int)); |
167 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3' |
168 | using Copy3Arr = Copy3[5]; |
169 | Copy3Arr c3a; |
170 | memset(c3a, 0, sizeof(c3a)); |
171 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr' |
172 | memset(&c3a, 0, sizeof(c3a)); |
173 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr' |
174 | |
175 | typedef Copy3 Copy3Arr2[5]; |
176 | Copy3Arr2 c3a2; |
177 | memset(c3a2, 0, sizeof(c3a2)); |
178 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr2' |
179 | } |
180 | |
181 | void triviallyCopyable() { |
182 | types::Plain p; |
183 | types::Base base; |
184 | types::Derived derived; |
185 | |
186 | int i = 5; |
187 | int ia[3] = {1, 2, 3}; |
188 | float f = 3.14; |
189 | float fa[3] = {1.1, 2.2, 3.3}; |
190 | bool b = false; |
191 | bool ba[2] = {true, false}; |
192 | types::E e = types::X; |
193 | p.n = 2; |
194 | |
195 | memset(&p, 0, sizeof(int)); |
196 | memset(&base, 0, sizeof(float)); |
197 | memset(&derived, 0, sizeof(bool)); |
198 | memset(&i, 0, sizeof(int)); |
199 | memset(ia, 0, sizeof(int)); |
200 | memset(&f, 0, sizeof(float)); |
201 | memset(fa, 0, sizeof(float)); |
202 | memset(&b, 0, sizeof(bool)); |
203 | memset(ba, 0, sizeof(bool)); |
204 | memset(&e, 0, sizeof(int)); |
205 | memset(&p.n, 0, sizeof(int)); |
206 | |
207 | memcpy(&p, &p, sizeof(int)); |
208 | memcpy(&base, &base, sizeof(float)); |
209 | memcpy(&derived, &derived, sizeof(bool)); |
210 | memcpy(&i, &i, sizeof(int)); |
211 | memcpy(ia, ia, sizeof(int)); |
212 | memcpy(&f, &f, sizeof(float)); |
213 | memcpy(fa, fa, sizeof(float)); |
214 | memcpy(&b, &b, sizeof(bool)); |
215 | memcpy(ba, ba, sizeof(bool)); |
216 | memcpy(&e, &e, sizeof(int)); |
217 | memcpy(&p.n, &p.n, sizeof(int)); |
218 | |
219 | memmove(&p, &p, sizeof(int)); |
220 | memmove(&base, &base, sizeof(float)); |
221 | memmove(&derived, &derived, sizeof(bool)); |
222 | memmove(&i, &i, sizeof(int)); |
223 | memmove(ia, ia, sizeof(int)); |
224 | memmove(&f, &f, sizeof(float)); |
225 | memmove(fa, fa, sizeof(float)); |
226 | memmove(&b, &b, sizeof(bool)); |
227 | memmove(ba, ba, sizeof(bool)); |
228 | memmove(&e, &e, sizeof(int)); |
229 | memmove(&p.n, &p.n, sizeof(int)); |
230 | } |
231 | |