1 // RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t 2 3 namespace gsl { 4 template <class T> 5 using owner = T; 6 } // namespace gsl 7 8 template <typename T> 9 class unique_ptr { 10 public: 11 unique_ptr(gsl::owner<T> resource) : memory(resource) {} 12 unique_ptr(const unique_ptr<T> &) = default; 13 14 ~unique_ptr() { delete memory; } 15 16 private: 17 gsl::owner<T> memory; 18 }; 19 20 void takes_owner(gsl::owner<int *> owned_int) { 21 } 22 23 void takes_pointer(int *unowned_int) { 24 } 25 26 void takes_owner_and_more(int some_int, gsl::owner<int *> owned_int, float f) { 27 } 28 29 template <typename T> 30 void takes_templated_owner(gsl::owner<T> owned_T) { 31 } 32 33 gsl::owner<int *> returns_owner1() { return gsl::owner<int *>(new int(42)); } // Ok 34 gsl::owner<int *> returns_owner2() { return new int(42); } // Ok 35 36 int *returns_no_owner1() { return nullptr; } 37 int *returns_no_owner2() { 38 return new int(42); 39 // CHECK-NOTES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>' 40 } 41 int *returns_no_owner3() { 42 int *should_be_owner = new int(42); 43 // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' 44 return should_be_owner; 45 } 46 int *returns_no_owner4() { 47 gsl::owner<int *> owner = new int(42); 48 return owner; 49 // CHECK-NOTES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>' 50 } 51 52 unique_ptr<int *> returns_no_owner5() { 53 return unique_ptr<int *>(new int(42)); // Ok 54 } 55 56 /// FIXME: CSA finds it, but the report is misleading. Ownersemantics can catch this 57 /// by flow analysis similar to bugprone-use-after-move. 58 void csa_not_finding_leak() { 59 gsl::owner<int *> o1 = new int(42); // Ok 60 61 gsl::owner<int *> o2 = o1; // Ok 62 o2 = new int(45); // conceptual leak, the memory from o1 is now leaked, since its considered moved in the guidelines 63 64 delete o2; 65 // actual leak occurs here, its found, but mixed 66 delete o1; 67 } 68 69 void test_assignment_and_initialization() { 70 int stack_int1 = 15; 71 int stack_int2; 72 73 gsl::owner<int *> owned_int1 = &stack_int1; // BAD 74 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' 75 76 gsl::owner<int *> owned_int2; 77 owned_int2 = &stack_int2; // BAD since no owner, bad since uninitialized 78 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *' 79 80 gsl::owner<int *> owned_int3 = new int(42); // Good 81 owned_int3 = nullptr; // Good 82 83 gsl::owner<int *> owned_int4(nullptr); // Ok 84 owned_int4 = new int(42); // Good 85 86 gsl::owner<int *> owned_int5 = owned_int3; // Good 87 88 gsl::owner<int *> owned_int6{nullptr}; // Ok 89 owned_int6 = owned_int4; // Good 90 91 // FIXME:, flow analysis for the case of reassignment. Value must be released before 92 owned_int6 = owned_int3; // BAD, because reassignment without resource release 93 94 auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper 95 96 const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper 97 98 gsl::owner<int *> owned_int9 = returns_owner1(); // Ok 99 int *unowned_int3 = returns_owner1(); // Bad 100 // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' 101 102 gsl::owner<int *> owned_int10; 103 owned_int10 = returns_owner1(); // Ok 104 105 int *unowned_int4; 106 unowned_int4 = returns_owner1(); // Bad 107 // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *' 108 109 gsl::owner<int *> owned_int11 = returns_no_owner1(); // Bad since no owner 110 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' 111 112 gsl::owner<int *> owned_int12; 113 owned_int12 = returns_no_owner1(); // Bad since no owner 114 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *' 115 116 int *unowned_int5 = returns_no_owner1(); // Ok 117 int *unowned_int6; 118 unowned_int6 = returns_no_owner1(); // Ok 119 120 int *unowned_int7 = new int(42); // Bad, since resource not assigned to an owner 121 // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' 122 123 int *unowned_int8; 124 unowned_int8 = new int(42); 125 // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *' 126 127 gsl::owner<int *> owned_int13 = nullptr; // Ok 128 } 129 130 void test_deletion() { 131 gsl::owner<int *> owned_int1 = new int(42); 132 delete owned_int1; // Good 133 134 gsl::owner<int *> owned_int2 = new int[42]; 135 delete[] owned_int2; // Good 136 137 int *unowned_int1 = new int(42); // BAD, since new creates and owner 138 // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' 139 delete unowned_int1; // BAD, since no owner 140 // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead 141 // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here 142 143 int *unowned_int2 = new int[42]; // BAD, since new creates and owner 144 // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' 145 delete[] unowned_int2; // BAD since no owner 146 // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead 147 // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here 148 149 delete new int(42); // Technically ok, but stupid 150 delete[] new int[42]; // Technically ok, but stupid 151 } 152 153 void test_owner_function_calls() { 154 int stack_int = 42; 155 int *unowned_int1 = &stack_int; 156 takes_owner(&stack_int); // BAD 157 // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *' 158 takes_owner(unowned_int1); // BAD 159 // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *' 160 161 gsl::owner<int *> owned_int1 = new int(42); 162 takes_owner(owned_int1); // Ok 163 164 takes_owner_and_more(42, &stack_int, 42.0f); // BAD 165 // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *' 166 takes_owner_and_more(42, unowned_int1, 42.0f); // BAD 167 // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *' 168 169 takes_owner_and_more(42, new int(42), 42.0f); // Ok, since new is consumed by owner 170 takes_owner_and_more(42, owned_int1, 42.0f); // Ok, since owner as argument 171 172 takes_templated_owner(owned_int1); // Ok 173 takes_templated_owner(new int(42)); // Ok 174 takes_templated_owner(unowned_int1); // Bad 175 // CHECK-NOTES: [[@LINE-1]]:25: warning: expected argument of type 'gsl::owner<>'; got 'int *' 176 177 takes_owner(returns_owner1()); // Ok 178 takes_owner(returns_no_owner1()); // BAD 179 // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *' 180 } 181 182 void test_unowned_function_calls() { 183 int stack_int = 42; 184 int *unowned_int1 = &stack_int; 185 gsl::owner<int *> owned_int1 = new int(42); 186 187 takes_pointer(&stack_int); // Ok 188 takes_pointer(unowned_int1); // Ok 189 takes_pointer(owned_int1); // Ok 190 takes_pointer(new int(42)); // Bad, since new creates and owner 191 // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>' 192 193 takes_pointer(returns_owner1()); // Bad 194 // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>' 195 196 takes_pointer(returns_no_owner1()); // Ok 197 } 198 199 // FIXME: Typedefing owner<> to something else does not work. 200 // This might be necessary for code already having a similar typedef like owner<> and 201 // replacing it with owner<>. This might be the same problem as with templates. 202 // The canonical type will ignore the owner<> alias, since its a typedef as well. 203 // 204 // Check, if owners hidden by typedef are handled the same as 'obvious' owners. 205 #if 0 206 using heap_int = gsl::owner<int *>; 207 typedef gsl::owner<float *> heap_float; 208 209 // This tests only a subset, assuming that the check will either see through the 210 // typedef or not (it doesn't!). 211 void test_typedefed_values() { 212 // Modern typedef. 213 int StackInt1 = 42; 214 heap_int HeapInt1 = &StackInt1; 215 // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *' 216 217 //FIXME: Typedef not considered correctly here. 218 // heap_int HeapInt2 = new int(42); // Ok 219 takes_pointer(HeapInt1); // Ok 220 takes_owner(HeapInt1); // Ok 221 222 // Traditional typedef. 223 float StackFloat1 = 42.0f; 224 heap_float HeapFloat1 = &StackFloat1; 225 // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'float *' 226 227 //FIXME: Typedef not considered correctly here. 228 // heap_float HeapFloat2 = new float(42.0f); 229 HeapFloat2 = HeapFloat1; // Ok 230 } 231 #endif 232 233 struct ArbitraryClass {}; 234 struct ClassWithOwner { // Does not define destructor, necessary with owner 235 ClassWithOwner() : owner_var(nullptr) {} // Ok 236 237 ClassWithOwner(ArbitraryClass &other) : owner_var(&other) {} 238 // CHECK-NOTES: [[@LINE-1]]:43: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'ArbitraryClass *' 239 240 ClassWithOwner(gsl::owner<ArbitraryClass *> other) : owner_var(other) {} // Ok 241 242 ClassWithOwner(gsl::owner<ArbitraryClass *> data, int /* unused */) { // Ok 243 owner_var = data; // Ok 244 } 245 246 ClassWithOwner(ArbitraryClass *bad_data, int /* unused */, int /* unused */) { 247 owner_var = bad_data; 248 // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *' 249 } 250 251 ClassWithOwner(ClassWithOwner &&other) : owner_var{other.owner_var} {} // Ok 252 253 ClassWithOwner &operator=(ClassWithOwner &&other) { 254 owner_var = other.owner_var; // Ok 255 return *this; 256 } 257 258 // Returning means, that the owner is "moved", so the class should not access this 259 // variable anymore after this method gets called. 260 gsl::owner<ArbitraryClass *> buggy_but_returns_owner() { return owner_var; } 261 262 gsl::owner<ArbitraryClass *> owner_var; 263 // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'ClassWithOwner' to implement a destructor to release the owned resource 264 }; 265 266 class DefaultedDestructor { // Bad since default constructor with owner 267 ~DefaultedDestructor() = default; // Bad, since will not destroy the owner 268 gsl::owner<int *> Owner; 269 // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DefaultedDestructor' to implement a destructor to release the owned resource 270 }; 271 272 struct DeletedDestructor { 273 ~DeletedDestructor() = delete; 274 gsl::owner<int *> Owner; 275 // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DeletedDestructor' to implement a destructor to release the owned resource 276 }; 277 278 void test_class_with_owner() { 279 ArbitraryClass A; 280 ClassWithOwner C1; // Ok 281 ClassWithOwner C2{A}; // Bad, since the owner would be initialized with an non-owner, but catched in the class 282 ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok 283 284 const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const 285 286 auto Owner2 = C2.buggy_but_returns_owner(); // Ok, deduces Owner2 to owner<ArbitraryClass *> 287 288 Owner2 = &A; // BAD, since type deduction resulted in owner<ArbitraryClass *> 289 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *' 290 291 gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner 292 Owner3 = &A; // Bad, since assignment of non-owner to owner 293 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *' 294 } 295 296 template <typename T> 297 struct HeapArray { // Ok, since destructor with owner 298 HeapArray() : _data(nullptr), size(0) {} // Ok 299 HeapArray(int size) : _data(new int[size]), size(size) {} // Ok 300 HeapArray(int size, T val) { 301 _data = new int[size]; // Ok 302 size = size; 303 for (auto i = 0u; i < size; ++i) 304 _data[i] = val; // Ok 305 } 306 HeapArray(int size, T val, int *problematic) : _data{problematic}, size(size) {} // Bad 307 // CHECK-NOTES: [[@LINE-1]]:50: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'void' 308 // FIXME: void is incorrect type, probably wrong thing matched 309 310 HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok 311 other._data = nullptr; // Ok 312 other.size = 0; 313 } 314 315 HeapArray<T> &operator=(HeapArray<T> &&other) { 316 _data = other._data; // Ok, NOLINT warning here about bad types, why? 317 size = other.size; 318 return *this; 319 } 320 321 ~HeapArray() { delete[] _data; } // Ok 322 323 T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory 324 325 gsl::owner<T *> _data; 326 unsigned int size; 327 }; 328 329 void test_inner_template() { 330 HeapArray<int> Array1; 331 HeapArray<int> Array2(100); 332 HeapArray<int> Array3(100, 0); 333 HeapArray<int> Array4(100, 0, nullptr); 334 335 Array1 = static_cast<HeapArray<int> &&>(Array2); 336 HeapArray<int> Array5(static_cast<HeapArray<int> &&>(Array3)); 337 338 int *NonOwningPtr = Array1.data(); // Ok 339 gsl::owner<int *> OwningPtr = Array1.data(); // Bad, since it does not return the owner 340 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' 341 } 342 343 // FIXME: Typededuction removes the owner - wrapper, therefore gsl::owner can not be used 344 // with Template classes like this. Is there a walkaround? 345 template <typename T> 346 struct TemplateValue { 347 TemplateValue() = default; 348 TemplateValue(T t) : val{t} {} 349 350 void setVal(const T &t) { val = t; } 351 const T getVal() const { return val; } 352 353 T val; 354 }; 355 356 // FIXME: Same typededcution problems 357 template <typename T> 358 void template_function(T t) { 359 gsl::owner<int *> owner_t = t; // Probably bad, since type deduction still wrong 360 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'T' 361 // CHECK-NOTES: [[@LINE-2]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' 362 } 363 364 // FIXME: Same typededcution problems 365 void test_templates() { 366 int stack_int = 42; 367 int *stack_ptr1 = &stack_int; 368 369 TemplateValue<gsl::owner<int *>> Owner0; // Ok, T should be owner, but is int* 370 371 TemplateValue<gsl::owner<int *>> Owner1(new int(42)); // Ok, T should be owner, but is int* 372 Owner1.setVal(&stack_int); // Bad since non-owner assignment 373 Owner1.setVal(stack_ptr1); // Bad since non-owner assignment 374 //Owner1.setVal(new int(42)); // Ok, but since type deduction is wrong, this one is considered harmful 375 376 int *stack_ptr2 = Owner1.getVal(); // Bad, initializing non-owner with owner 377 378 TemplateValue<int *> NonOwner1(new int(42)); // Bad, T is int *, hence dynamic memory to non-owner 379 gsl::owner<int *> IntOwner1 = NonOwner1.getVal(); // Bad, since owner initialized with non-owner 380 // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' 381 382 template_function(IntOwner1); // Ok, but not actually ok, since type deduction removes owner 383 template_function(stack_ptr1); // Bad, but type deduction gets it wrong 384 } 385