| 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 | |