forked from OSchip/llvm-project
214 lines
6.6 KiB
C++
214 lines
6.6 KiB
C++
|
// 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 <typename T>
|
||
|
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 <typename S, typename T>
|
||
|
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 <typename S, typename T>
|
||
|
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<types::VirtualFunc>(&vf);
|
||
|
memcpy_temp<types::Plain, types::VirtualFunc>(&p, &vf);
|
||
|
memmove_temp<types::Plain, types::VirtualFunc>(&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));
|
||
|
}
|