brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.5 KiB · 154013d Raw
100 lines · plain
1.. title:: clang-tidy - bugprone-multiple-new-in-one-expression2 3bugprone-multiple-new-in-one-expression4=======================================5 6Finds multiple ``new`` operator calls in a single expression, where the7allocated memory by the first ``new`` may leak if the second allocation fails8and throws exception.9 10C++ does often not specify the exact order of evaluation of the operands of an11operator or arguments of a function. Therefore if a first allocation succeeds12and a second fails, in an exception handler it is not possible to tell which13allocation has failed and free the memory. Even if the order is fixed the14result of a first ``new`` may be stored in a temporary location that is not15reachable at the time when a second allocation fails. It is best to avoid any16expression that contains more than one ``operator new`` call, if exception17handling is used to check for allocation errors.18 19Different rules apply for are the short-circuit operators ``||`` and ``&&`` and20the ``,`` operator, where evaluation of one side must be completed before the21other starts. Expressions of a list-initialization (initialization or22construction using ``{`` and ``}`` characters) are evaluated in fixed order.23Similarly, condition of a ``?`` operator is evaluated before the branches are24evaluated.25 26The check reports warning if two ``new`` calls appear in one expression at27different sides of an operator, or if ``new`` calls appear in different28arguments of a function call (that can be an object construction with ``()``29syntax). These ``new`` calls can be nested at any level.30For any warning to be emitted the ``new`` calls should be in a code block where31exception handling is used with catch for ``std::bad_alloc`` or32``std::exception``. At ``||``, ``&&``, ``,``, ``?`` (condition and one branch)33operators no warning is emitted. No warning is emitted if both of the memory34allocations are not assigned to a variable or not passed directly to a35function. The reason is that in this case the memory may be intentionally not36freed or the allocated objects can be self-destructing objects.37 38Examples:39 40.. code-block:: c++41 42  struct A {43    int Var;44  };45  struct B {46    B();47    B(A *);48    int Var;49  };50  struct C {51    int *X1;52    int *X2;53  };54 55  void f(A *, B *);56  int f1(A *);57  int f1(B *);58  bool f2(A *);59 60  void foo() {61    A *PtrA;62    B *PtrB;63    try {64      // Allocation of 'B'/'A' may fail after memory for 'A'/'B' was allocated.65      f(new A, new B); // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; order of these allocations is undefined66 67      // List (aggregate) initialization is used.68      C C1{new int, new int}; // no warning69 70      // Allocation of 'B'/'A' may fail after memory for 'A'/'B' was allocated but not yet passed to function 'f1'.71      int X = f1(new A) + f1(new B); // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; order of these allocations is undefined72 73      // Allocation of 'B' may fail after memory for 'A' was allocated.74      // From C++17 on memory for 'B' is allocated first but still may leak if allocation of 'A' fails.75      PtrB = new B(new A); // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception76 77      // 'new A' and 'new B' may be performed in any order.78      // 'new B'/'new A' may fail after memory for 'A'/'B' was allocated but not assigned to 'PtrA'/'PtrB'.79      (PtrA = new A)->Var = (PtrB = new B)->Var; // warning: memory allocation may leak if an other allocation is sequenced after it and throws an exception; order of these allocations is undefined80 81      // Evaluation of 'f2(new A)' must be finished before 'f1(new B)' starts.82      // If 'new B' fails the allocated memory for 'A' is supposedly handled correctly because function 'f2' could take the ownership.83      bool Z = f2(new A) || f1(new B); // no warning84 85      X = (f2(new A) ? f1(new A) : f1(new B)); // no warning86 87      // No warning if the result of both allocations is not passed to a function88      // or stored in a variable.89      (new A)->Var = (new B)->Var; // no warning90 91      // No warning if at least one non-throwing allocation is used.92      f(new(std::nothrow) A, new B); // no warning93    } catch(std::bad_alloc) {94    }95 96    // No warning if the allocation is outside a try block (or no catch handler exists for std::bad_alloc).97    // (The fact if exceptions can escape from 'foo' is not taken into account.)98    f(new A, new B); // no warning99  }100