// RUN: %check_clang_tidy %s bugprone-undefined-memory-manipulation %t void *memset(void *, int, __SIZE_TYPE__); void *memcpy(void *, const void *, __SIZE_TYPE__); void *memmove(void *, const void *, __SIZE_TYPE__); namespace std { using ::memcpy; using ::memmove; using ::memset; } namespace types { // TriviallyCopyable types: struct Plain { int n; }; enum E { X, Y, Z }; struct Base { float b; }; struct Derived : Base { bool d; }; // not TriviallyCopyable types: struct Destruct { ~Destruct() {} }; struct Copy { Copy() {} Copy(const Copy &) {} }; struct Move { Move() {} Move(Move &&) {} }; struct VirtualFunc { virtual void f() {} }; struct VirtualBase : virtual Base { int vb; }; // Incomplete type, assume it is TriviallyCopyable. struct NoDef; } // end namespace types void f(types::NoDef *s) { memset(s, 0, 5); } template void memset_temp(T *b) { memset(b, 0, sizeof(T)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' is not TriviallyCopyable [bugprone-undefined-memory-manipulation] } template void memcpy_temp(S *a, T *b) { memcpy(a, b, sizeof(T)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc' } template void memmove_temp(S *a, T *b) { memmove(a, b, sizeof(T)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc' } namespace aliases { using Copy2 = types::Copy; typedef types::Move Move2; } void notTriviallyCopyable() { types::Plain p; // TriviallyCopyable for variety types::Destruct d; types::Copy c; types::Move m; types::VirtualFunc vf; types::VirtualBase vb; memset(&vf, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' memset(&d, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct' memset(&c, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy' std::memset(&m, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move' ::memset(&vb, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase' memcpy(&p, &vf, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc' memcpy(&p, &d, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Destruct' memcpy(&c, &p, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy' std::memcpy(&m, &p, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move' ::memcpy(&vb, &p, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase' memmove(&vf, &p, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' memmove(&d, &p, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct' memmove(&p, &c, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy' std::memmove(&p, &m, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Move' ::memmove(&p, &vb, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualBase' #define MEMSET memset(&vf, 0, sizeof(int)); MEMSET // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' #define MEMCPY memcpy(&d, &p, sizeof(int)); MEMCPY // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct' #define MEMMOVE memmove(&p, &c, sizeof(int)); MEMMOVE // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy' memset_temp(&vf); memcpy_temp(&p, &vf); memmove_temp(&p, &vf); aliases::Copy2 c2; aliases::Move2 m2; memset(&c2, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2' memset(&m2, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Move2' typedef aliases::Copy2 Copy3; typedef aliases::Copy2 *PCopy2; typedef Copy3 *PCopy3; Copy3 c3; PCopy2 pc2; PCopy3 pc3; memset(&c3, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3' memset(pc2, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2' memset(pc3, 0, sizeof(int)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3' } void triviallyCopyable() { types::Plain p; types::Base base; types::Derived derived; int i = 5; int ia[3] = {1, 2, 3}; float f = 3.14; float fa[3] = {1.1, 2.2, 3.3}; bool b = false; bool ba[2] = {true, false}; types::E e = types::X; p.n = 2; memset(&p, 0, sizeof(int)); memset(&base, 0, sizeof(float)); memset(&derived, 0, sizeof(bool)); memset(&i, 0, sizeof(int)); memset(ia, 0, sizeof(int)); memset(&f, 0, sizeof(float)); memset(fa, 0, sizeof(float)); memset(&b, 0, sizeof(bool)); memset(ba, 0, sizeof(bool)); memset(&e, 0, sizeof(int)); memset(&p.n, 0, sizeof(int)); memcpy(&p, &p, sizeof(int)); memcpy(&base, &base, sizeof(float)); memcpy(&derived, &derived, sizeof(bool)); memcpy(&i, &i, sizeof(int)); memcpy(ia, ia, sizeof(int)); memcpy(&f, &f, sizeof(float)); memcpy(fa, fa, sizeof(float)); memcpy(&b, &b, sizeof(bool)); memcpy(ba, ba, sizeof(bool)); memcpy(&e, &e, sizeof(int)); memcpy(&p.n, &p.n, sizeof(int)); memmove(&p, &p, sizeof(int)); memmove(&base, &base, sizeof(float)); memmove(&derived, &derived, sizeof(bool)); memmove(&i, &i, sizeof(int)); memmove(ia, ia, sizeof(int)); memmove(&f, &f, sizeof(float)); memmove(fa, fa, sizeof(float)); memmove(&b, &b, sizeof(bool)); memmove(ba, ba, sizeof(bool)); memmove(&e, &e, sizeof(int)); memmove(&p.n, &p.n, sizeof(int)); }