brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.6 KiB · ae61b17 Raw
506 lines · cpp
1// RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t2 3namespace gsl {4template <class T>5using owner = T;6} // namespace gsl7 8template <typename T>9class unique_ptr {10public:11  unique_ptr(gsl::owner<T> resource) : memory(resource) {}12  unique_ptr(const unique_ptr<T> &) = default;13 14  ~unique_ptr() { delete memory; }15 16private:17  gsl::owner<T> memory;18};19 20void takes_owner(gsl::owner<int *> owned_int) {21}22 23void takes_pointer(int *unowned_int) {24}25 26void takes_owner_and_more(int some_int, gsl::owner<int *> owned_int, float f) {27}28 29template <typename T>30void takes_templated_owner(gsl::owner<T> owned_T) {31}32 33gsl::owner<int *> returns_owner1() { return gsl::owner<int *>(new int(42)); } // Ok34gsl::owner<int *> returns_owner2() { return new int(42); }                    // Ok35 36int *returns_no_owner1() { return nullptr; }37int *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}41int *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}46int *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 52unique_ptr<int *> returns_no_owner5() {53  return unique_ptr<int *>(new int(42)); // Ok54}55 56/// FIXME: CSA finds it, but the report is misleading. Ownersemantics can catch this57/// by flow analysis similar to bugprone-use-after-move.58void csa_not_finding_leak() {59  gsl::owner<int *> o1 = new int(42); // Ok60 61  gsl::owner<int *> o2 = o1; // Ok62  o2 = new int(45);          // conceptual leak, the memory from o1 is now leaked, since its considered moved in the guidelines63 64  delete o2;65  // actual leak occurs here, its found, but mixed66  delete o1;67}68 69void test_assignment_and_initialization() {70  int stack_int1 = 15;71  int stack_int2;72 73  gsl::owner<int *> owned_int1 = &stack_int1; // BAD74  // 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 uninitialized78  // 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); // Good81  owned_int3 = nullptr;                       // Good82 83  gsl::owner<int *> owned_int4(nullptr); // Ok84  owned_int4 = new int(42);              // Good85 86  gsl::owner<int *> owned_int5 = owned_int3; // Good87 88  gsl::owner<int *> owned_int6{nullptr}; // Ok89  owned_int6 = owned_int4;               // Good90 91  // FIXME:, flow analysis for the case of reassignment. Value must be released before92  owned_int6 = owned_int3; // BAD, because reassignment without resource release93 94  auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper95 96  const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper97 98  gsl::owner<int *> owned_int9 = returns_owner1(); // Ok99  int *unowned_int3 = returns_owner1();            // Bad100  // 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(); // Ok104 105  int *unowned_int4;106  unowned_int4 = returns_owner1(); // Bad107  // 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 owner110  // 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 owner114  // 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(); // Ok117  int *unowned_int6;118  unowned_int6 = returns_no_owner1(); // Ok119 120  int *unowned_int7 = new int(42); // Bad, since resource not assigned to an owner121  // 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; // Ok128}129 130void test_deletion() {131  gsl::owner<int *> owned_int1 = new int(42);132  delete owned_int1; // Good133 134  gsl::owner<int *> owned_int2 = new int[42];135  delete[] owned_int2; // Good136 137  int *unowned_int1 = new int(42); // BAD, since new creates and owner138  // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'139  delete unowned_int1; // BAD, since no owner140  // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead141  // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here142 143  int *unowned_int2 = new int[42]; // BAD, since new creates and owner144  // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'145  delete[] unowned_int2; // BAD since no owner146  // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead147  // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here148 149  delete new int(42);   // Technically ok, but stupid150  delete[] new int[42]; // Technically ok, but stupid151}152 153void test_owner_function_calls() {154  int stack_int = 42;155  int *unowned_int1 = &stack_int;156  takes_owner(&stack_int); // BAD157  // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'158  takes_owner(unowned_int1); // BAD159  // 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); // Ok163 164  takes_owner_and_more(42, &stack_int, 42.0f); // BAD165  // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'166  takes_owner_and_more(42, unowned_int1, 42.0f); // BAD167  // 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 owner170  takes_owner_and_more(42, owned_int1, 42.0f);  // Ok, since owner as argument171 172  takes_templated_owner(owned_int1);   // Ok173  takes_templated_owner(new int(42));  // Ok174  takes_templated_owner(unowned_int1); // Bad175  // CHECK-NOTES: [[@LINE-1]]:25: warning: expected argument of type 'gsl::owner<>'; got 'int *'176 177  takes_owner(returns_owner1());    // Ok178  takes_owner(returns_no_owner1()); // BAD179  // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'180}181 182void 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);   // Ok188  takes_pointer(unowned_int1); // Ok189  takes_pointer(owned_int1);   // Ok190  takes_pointer(new int(42));  // Bad, since new creates and owner191  // 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()); // Bad194  // 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()); // Ok197}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<> and201// 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 0206using heap_int = gsl::owner<int *>;207typedef gsl::owner<float *> heap_float;208 209// This tests only a subset, assuming that the check will either see through the210// typedef or not (it doesn't!).211void 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); // Ok219  takes_pointer(HeapInt1); // Ok220  takes_owner(HeapInt1);   // Ok221 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; // Ok230}231#endif232 233struct ArbitraryClass {};234struct ClassWithOwner {                    // Does not define destructor, necessary with owner235  ClassWithOwner() : owner_var(nullptr) {} // Ok236 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) {} // Ok241 242  ClassWithOwner(gsl::owner<ArbitraryClass *> data, int /* unused */) { // Ok243    owner_var = data;                                                   // Ok244  }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} {} // Ok252 253  ClassWithOwner &operator=(ClassWithOwner &&other) {254    owner_var = other.owner_var; // Ok255    return *this;256  }257 258  // Returning means, that the owner is "moved", so the class should not access this259  // 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 resource264};265 266class DefaultedDestructor {         // Bad since default constructor with owner267  ~DefaultedDestructor() = default; // Bad, since will not destroy the owner268  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 resource270};271 272struct 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 resource276};277 278void test_class_with_owner() {279  ArbitraryClass A;280  ClassWithOwner C1;                                                   // Ok281  ClassWithOwner C2{A};                                                // Bad, since the owner would be initialized with an non-owner, but catched in the class282  ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok283 284  const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const285 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 owner292  Owner3 = &A;                                                        // Bad, since assignment of non-owner to owner293  // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'294}295 296template <typename T>297struct HeapArray {                                          // Ok, since destructor with owner298  HeapArray() : _data(nullptr), size(0) {}                  // Ok299  HeapArray(int size) : _data(new int[size]), size(size) {} // Ok300  HeapArray(int size, T val) {301    _data = new int[size]; // Ok302    size = size;303    for (auto i = 0u; i < size; ++i)304      _data[i] = val; // Ok305  }306  HeapArray(int size, T val, int *problematic) : _data{problematic}, size(size) {} // Bad307  // 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 matched309 310  HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok311    other._data = nullptr;                                              // Ok312    // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'313    // FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types.314    other.size = 0;315  }316 317  HeapArray<T> &operator=(HeapArray<T> &&other) {318    _data = other._data; // Ok, NOLINT warning here about bad types, why?319    size = other.size;320    return *this;321  }322 323  ~HeapArray() { delete[] _data; } // Ok324 325  T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory326 327  gsl::owner<T *> _data;328  unsigned int size;329};330 331void test_inner_template() {332  HeapArray<int> Array1;333  HeapArray<int> Array2(100);334  HeapArray<int> Array3(100, 0);335  HeapArray<int> Array4(100, 0, nullptr);336 337  Array1 = static_cast<HeapArray<int> &&>(Array2);338  HeapArray<int> Array5(static_cast<HeapArray<int> &&>(Array3));339 340  int *NonOwningPtr = Array1.data();           // Ok341  gsl::owner<int *> OwningPtr = Array1.data(); // Bad, since it does not return the owner342  // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'343}344 345// FIXME: Typededuction removes the owner - wrapper, therefore gsl::owner can not be used346// with Template classes like this. Is there a walkaround?347template <typename T>348struct TemplateValue {349  TemplateValue() = default;350  TemplateValue(T t) : val{t} {}351 352  void setVal(const T &t) { val = t; }353  const T getVal() const { return val; }354 355  T val;356};357 358// FIXME: Same typededcution problems359template <typename T>360void template_function(T t) {361  gsl::owner<int *> owner_t = t; // Probably bad, since type deduction still wrong362  // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'T'363  // CHECK-NOTES: [[@LINE-2]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'364}365 366// FIXME: Same typededcution problems367void test_templates() {368  int stack_int = 42;369  int *stack_ptr1 = &stack_int;370 371  TemplateValue<gsl::owner<int *>> Owner0; // Ok, T should be owner, but is int*372 373  TemplateValue<gsl::owner<int *>> Owner1(new int(42)); // Ok, T should be owner, but is int*374  Owner1.setVal(&stack_int);                            // Bad since non-owner assignment375  Owner1.setVal(stack_ptr1);                            // Bad since non-owner assignment376  //Owner1.setVal(new int(42)); // Ok, but since type deduction is wrong, this one is considered harmful377 378  int *stack_ptr2 = Owner1.getVal(); // Bad, initializing non-owner with owner379 380  TemplateValue<int *> NonOwner1(new int(42));      // Bad, T is int *, hence dynamic memory to non-owner381  gsl::owner<int *> IntOwner1 = NonOwner1.getVal(); // Bad, since owner initialized with non-owner382  // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'383 384  template_function(IntOwner1);  // Ok, but not actually ok, since type deduction removes owner385  template_function(stack_ptr1); // Bad, but type deduction gets it wrong386}387 388namespace PR63994 {389  struct A {390    virtual ~A() {}391  };392 393  struct B : public A {};394 395  A* foo(int x) {396    return new B;397    // CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'A *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'398  }399}400 401namespace PR59389 {402  struct S {403    S();404    S(int);405 406    int value = 1;407  };408 409  void testLambdaInFunctionNegative() {410    const auto MakeS = []() -> ::gsl::owner<S*> {411      return ::gsl::owner<S*>{new S{}};412    };413  }414 415  void testLambdaInFunctionPositive() {416    const auto MakeS = []() -> S* {417      return ::gsl::owner<S*>{new S{}};418      // CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'419    };420  }421 422  void testFunctionInFunctionNegative() {423    struct C {424      ::gsl::owner<S*> test() {425        return ::gsl::owner<S*>{new S{}};426      }427    };428  }429 430  void testFunctionInFunctionPositive() {431    struct C {432      S* test() {433        return ::gsl::owner<S*>{new S{}};434        // CHECK-NOTES: [[@LINE-1]]:9: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'435      }436    };437  }438 439  ::gsl::owner<S*> testReverseLambdaNegative() {440    const auto MakeI = [] -> int { return 5; };441    return ::gsl::owner<S*>{new S(MakeI())};442  }443 444  S* testReverseLambdaPositive() {445    const auto MakeI = [] -> int { return 5; };446    return ::gsl::owner<S*>{new S(MakeI())};447    // CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'448  }449 450  ::gsl::owner<S*> testReverseFunctionNegative() {451    struct C {452      int test() { return 5; }453    };454    return ::gsl::owner<S*>{new S(C().test())};455  }456 457  S* testReverseFunctionPositive() {458    struct C {459      int test() { return 5; }460    };461    return ::gsl::owner<S*>{new S(C().test())};462    // CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'463  }464 465  void testLambdaInLambdaNegative() {466    const auto MakeS = []() -> ::gsl::owner<S*> {467      const auto MakeI = []() -> int { return 5; };468      return ::gsl::owner<S*>{new S(MakeI())};469    };470  }471 472  void testLambdaInLambdaPositive() {473    const auto MakeS = []() -> S* {474      const auto MakeI = []() -> int { return 5; };475      return ::gsl::owner<S*>{new S(MakeI())};476      // CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'477    };478  }479 480  void testLambdaInLambdaWithDoubleReturns() {481    const auto MakeS = []() -> S* {482      const auto MakeS2 = []() -> S* {483        return ::gsl::owner<S*>{new S(1)};484        // CHECK-NOTES: [[@LINE-1]]:9: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>' [cppcoreguidelines-owning-memory]485      };486      return ::gsl::owner<S*>{new S(2)};487      // CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'488    };489  }490 491  void testReverseLambdaInLambdaNegative() {492    const auto MakeI = []() -> int {493      const auto MakeS = []() -> ::gsl::owner<S*> { return new S(); };494      return 5;495    };496  }497 498  void testReverseLambdaInLambdaPositive() {499    const auto MakeI = []() -> int {500      const auto MakeS = []() -> S* { return new S(); };501      // CHECK-NOTES: [[@LINE-1]]:39: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'502      return 5;503    };504  }505}506