189a1d03eSRichard // RUN: %check_clang_tidy %s bugprone-undefined-memory-manipulation %t
289a1d03eSRichard 
389a1d03eSRichard void *memset(void *, int, __SIZE_TYPE__);
489a1d03eSRichard void *memcpy(void *, const void *, __SIZE_TYPE__);
589a1d03eSRichard void *memmove(void *, const void *, __SIZE_TYPE__);
689a1d03eSRichard 
789a1d03eSRichard namespace std {
889a1d03eSRichard using ::memcpy;
989a1d03eSRichard using ::memmove;
1089a1d03eSRichard using ::memset;
1189a1d03eSRichard }
1289a1d03eSRichard 
1389a1d03eSRichard namespace types {
1489a1d03eSRichard // TriviallyCopyable types:
1589a1d03eSRichard struct Plain {
1689a1d03eSRichard   int n;
1789a1d03eSRichard };
1889a1d03eSRichard 
1989a1d03eSRichard enum E {
2089a1d03eSRichard   X,
2189a1d03eSRichard   Y,
2289a1d03eSRichard   Z
2389a1d03eSRichard };
2489a1d03eSRichard 
2589a1d03eSRichard struct Base {
2689a1d03eSRichard   float b;
2789a1d03eSRichard };
2889a1d03eSRichard 
2989a1d03eSRichard struct Derived : Base {
3089a1d03eSRichard   bool d;
3189a1d03eSRichard };
3289a1d03eSRichard 
3389a1d03eSRichard // not TriviallyCopyable types:
3489a1d03eSRichard struct Destruct {
~Destructtypes::Destruct3589a1d03eSRichard   ~Destruct() {}
3689a1d03eSRichard };
3789a1d03eSRichard 
3889a1d03eSRichard struct Copy {
Copytypes::Copy3989a1d03eSRichard   Copy() {}
Copytypes::Copy4089a1d03eSRichard   Copy(const Copy &) {}
4189a1d03eSRichard };
4289a1d03eSRichard 
4389a1d03eSRichard struct Move {
Movetypes::Move4489a1d03eSRichard   Move() {}
Movetypes::Move4589a1d03eSRichard   Move(Move &&) {}
4689a1d03eSRichard };
4789a1d03eSRichard 
4889a1d03eSRichard struct VirtualFunc {
ftypes::VirtualFunc4989a1d03eSRichard   virtual void f() {}
5089a1d03eSRichard };
5189a1d03eSRichard 
5289a1d03eSRichard struct VirtualBase : virtual Base {
5389a1d03eSRichard   int vb;
5489a1d03eSRichard };
5589a1d03eSRichard 
5689a1d03eSRichard // Incomplete type, assume it is TriviallyCopyable.
5789a1d03eSRichard struct NoDef;
5889a1d03eSRichard 
5989a1d03eSRichard } // end namespace types
6089a1d03eSRichard 
f(types::NoDef * s)6189a1d03eSRichard void f(types::NoDef *s) {
6289a1d03eSRichard   memset(s, 0, 5);
6389a1d03eSRichard }
6489a1d03eSRichard 
6589a1d03eSRichard template <typename T>
memset_temp(T * b)6689a1d03eSRichard void memset_temp(T *b) {
6789a1d03eSRichard   memset(b, 0, sizeof(T));
6889a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' is not TriviallyCopyable [bugprone-undefined-memory-manipulation]
6989a1d03eSRichard }
7089a1d03eSRichard 
7189a1d03eSRichard template <typename S, typename T>
memcpy_temp(S * a,T * b)7289a1d03eSRichard void memcpy_temp(S *a, T *b) {
7389a1d03eSRichard   memcpy(a, b, sizeof(T));
7489a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
7589a1d03eSRichard }
7689a1d03eSRichard 
7789a1d03eSRichard template <typename S, typename T>
memmove_temp(S * a,T * b)7889a1d03eSRichard void memmove_temp(S *a, T *b) {
7989a1d03eSRichard   memmove(a, b, sizeof(T));
8089a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
8189a1d03eSRichard }
8289a1d03eSRichard 
8389a1d03eSRichard namespace aliases {
8489a1d03eSRichard using Copy2 = types::Copy;
8589a1d03eSRichard typedef types::Move Move2;
8689a1d03eSRichard }
8789a1d03eSRichard 
notTriviallyCopyable()8889a1d03eSRichard void notTriviallyCopyable() {
8989a1d03eSRichard   types::Plain p; // TriviallyCopyable for variety
9089a1d03eSRichard   types::Destruct d;
9189a1d03eSRichard   types::Copy c;
9289a1d03eSRichard   types::Move m;
9389a1d03eSRichard   types::VirtualFunc vf;
9489a1d03eSRichard   types::VirtualBase vb;
9589a1d03eSRichard 
9689a1d03eSRichard   memset(&vf, 0, sizeof(int));
9789a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
9889a1d03eSRichard   memset(&d, 0, sizeof(int));
9989a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
10089a1d03eSRichard   memset(&c, 0, sizeof(int));
10189a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy'
10289a1d03eSRichard   std::memset(&m, 0, sizeof(int));
10389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move'
10489a1d03eSRichard   ::memset(&vb, 0, sizeof(int));
10589a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase'
10689a1d03eSRichard 
10789a1d03eSRichard   memcpy(&p, &vf, sizeof(int));
10889a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
10989a1d03eSRichard   memcpy(&p, &d, sizeof(int));
11089a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Destruct'
11189a1d03eSRichard   memcpy(&c, &p, sizeof(int));
11289a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy'
11389a1d03eSRichard   std::memcpy(&m, &p, sizeof(int));
11489a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move'
11589a1d03eSRichard   ::memcpy(&vb, &p, sizeof(int));
11689a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase'
11789a1d03eSRichard 
11889a1d03eSRichard   memmove(&vf, &p, sizeof(int));
11989a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
12089a1d03eSRichard   memmove(&d, &p, sizeof(int));
12189a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
12289a1d03eSRichard   memmove(&p, &c, sizeof(int));
12389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy'
12489a1d03eSRichard   std::memmove(&p, &m, sizeof(int));
12589a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Move'
12689a1d03eSRichard   ::memmove(&p, &vb, sizeof(int));
12789a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualBase'
12889a1d03eSRichard 
129*6780d53fSFabian Wolff   types::Copy ca[10];
130*6780d53fSFabian Wolff   memset(ca, 0, sizeof(ca));
131*6780d53fSFabian Wolff   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]'
132*6780d53fSFabian Wolff   memset(&ca, 0, sizeof(ca));
133*6780d53fSFabian Wolff   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy[10]'
134*6780d53fSFabian Wolff 
13589a1d03eSRichard #define MEMSET memset(&vf, 0, sizeof(int));
13689a1d03eSRichard   MEMSET
13789a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
13889a1d03eSRichard #define MEMCPY memcpy(&d, &p, sizeof(int));
13989a1d03eSRichard   MEMCPY
14089a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
14189a1d03eSRichard #define MEMMOVE memmove(&p, &c, sizeof(int));
14289a1d03eSRichard   MEMMOVE
14389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy'
14489a1d03eSRichard 
14589a1d03eSRichard   memset_temp<types::VirtualFunc>(&vf);
14689a1d03eSRichard   memcpy_temp<types::Plain, types::VirtualFunc>(&p, &vf);
14789a1d03eSRichard   memmove_temp<types::Plain, types::VirtualFunc>(&p, &vf);
14889a1d03eSRichard 
14989a1d03eSRichard   aliases::Copy2 c2;
15089a1d03eSRichard   aliases::Move2 m2;
15189a1d03eSRichard   memset(&c2, 0, sizeof(int));
15289a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
15389a1d03eSRichard   memset(&m2, 0, sizeof(int));
15489a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Move2'
15589a1d03eSRichard 
15689a1d03eSRichard   typedef aliases::Copy2 Copy3;
15789a1d03eSRichard   typedef aliases::Copy2 *PCopy2;
15889a1d03eSRichard   typedef Copy3 *PCopy3;
15989a1d03eSRichard   Copy3 c3;
16089a1d03eSRichard   PCopy2 pc2;
16189a1d03eSRichard   PCopy3 pc3;
16289a1d03eSRichard   memset(&c3, 0, sizeof(int));
16389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
16489a1d03eSRichard   memset(pc2, 0, sizeof(int));
16589a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
16689a1d03eSRichard   memset(pc3, 0, sizeof(int));
16789a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
168*6780d53fSFabian Wolff   using Copy3Arr = Copy3[5];
169*6780d53fSFabian Wolff   Copy3Arr c3a;
170*6780d53fSFabian Wolff   memset(c3a, 0, sizeof(c3a));
171*6780d53fSFabian Wolff   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr'
172*6780d53fSFabian Wolff   memset(&c3a, 0, sizeof(c3a));
173*6780d53fSFabian Wolff   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr'
174*6780d53fSFabian Wolff 
175*6780d53fSFabian Wolff   typedef Copy3 Copy3Arr2[5];
176*6780d53fSFabian Wolff   Copy3Arr2 c3a2;
177*6780d53fSFabian Wolff   memset(c3a2, 0, sizeof(c3a2));
178*6780d53fSFabian Wolff   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3Arr2'
17989a1d03eSRichard }
18089a1d03eSRichard 
triviallyCopyable()18189a1d03eSRichard void triviallyCopyable() {
18289a1d03eSRichard   types::Plain p;
18389a1d03eSRichard   types::Base base;
18489a1d03eSRichard   types::Derived derived;
18589a1d03eSRichard 
18689a1d03eSRichard   int i = 5;
18789a1d03eSRichard   int ia[3] = {1, 2, 3};
18889a1d03eSRichard   float f = 3.14;
18989a1d03eSRichard   float fa[3] = {1.1, 2.2, 3.3};
19089a1d03eSRichard   bool b = false;
19189a1d03eSRichard   bool ba[2] = {true, false};
19289a1d03eSRichard   types::E e = types::X;
19389a1d03eSRichard   p.n = 2;
19489a1d03eSRichard 
19589a1d03eSRichard   memset(&p, 0, sizeof(int));
19689a1d03eSRichard   memset(&base, 0, sizeof(float));
19789a1d03eSRichard   memset(&derived, 0, sizeof(bool));
19889a1d03eSRichard   memset(&i, 0, sizeof(int));
19989a1d03eSRichard   memset(ia, 0, sizeof(int));
20089a1d03eSRichard   memset(&f, 0, sizeof(float));
20189a1d03eSRichard   memset(fa, 0, sizeof(float));
20289a1d03eSRichard   memset(&b, 0, sizeof(bool));
20389a1d03eSRichard   memset(ba, 0, sizeof(bool));
20489a1d03eSRichard   memset(&e, 0, sizeof(int));
20589a1d03eSRichard   memset(&p.n, 0, sizeof(int));
20689a1d03eSRichard 
20789a1d03eSRichard   memcpy(&p, &p, sizeof(int));
20889a1d03eSRichard   memcpy(&base, &base, sizeof(float));
20989a1d03eSRichard   memcpy(&derived, &derived, sizeof(bool));
21089a1d03eSRichard   memcpy(&i, &i, sizeof(int));
21189a1d03eSRichard   memcpy(ia, ia, sizeof(int));
21289a1d03eSRichard   memcpy(&f, &f, sizeof(float));
21389a1d03eSRichard   memcpy(fa, fa, sizeof(float));
21489a1d03eSRichard   memcpy(&b, &b, sizeof(bool));
21589a1d03eSRichard   memcpy(ba, ba, sizeof(bool));
21689a1d03eSRichard   memcpy(&e, &e, sizeof(int));
21789a1d03eSRichard   memcpy(&p.n, &p.n, sizeof(int));
21889a1d03eSRichard 
21989a1d03eSRichard   memmove(&p, &p, sizeof(int));
22089a1d03eSRichard   memmove(&base, &base, sizeof(float));
22189a1d03eSRichard   memmove(&derived, &derived, sizeof(bool));
22289a1d03eSRichard   memmove(&i, &i, sizeof(int));
22389a1d03eSRichard   memmove(ia, ia, sizeof(int));
22489a1d03eSRichard   memmove(&f, &f, sizeof(float));
22589a1d03eSRichard   memmove(fa, fa, sizeof(float));
22689a1d03eSRichard   memmove(&b, &b, sizeof(bool));
22789a1d03eSRichard   memmove(ba, ba, sizeof(bool));
22889a1d03eSRichard   memmove(&e, &e, sizeof(int));
22989a1d03eSRichard   memmove(&p.n, &p.n, sizeof(int));
23089a1d03eSRichard }
231