1.. title:: clang-tidy - bugprone-multiple-new-in-one-expression 2 3bugprone-multiple-new-in-one-expression 4======================================= 5 6Finds multiple ``new`` operator calls in a single expression, where the 7allocated memory by the first ``new`` may leak if the second allocation fails 8and throws exception. 9 10C++ does often not specify the exact order of evaluation of the operands of an 11operator or arguments of a function. Therefore if a first allocation succeeds 12and a second fails, in an exception handler it is not possible to tell which 13allocation has failed and free the memory. Even if the order is fixed the result 14of a first ``new`` may be stored in a temporary location that is not reachable 15at the time when a second allocation fails. It is best to avoid any expression 16that contains more than one ``operator new`` call, if exception handling is 17used to check for allocation errors. 18 19Different rules apply for are the short-circuit operators ``||`` and ``&&`` and 20the ``,`` operator, where evaluation of one side must be completed before the 21other starts. Expressions of a list-initialization (initialization or 22construction using ``{`` and ``}`` characters) are evaluated in fixed order. 23Similarly, condition of a ``?`` operator is evaluated before the branches are 24evaluated. 25 26The check reports warning if two ``new`` calls appear in one expression at 27different sides of an operator, or if ``new`` calls appear in different 28arguments 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 where 31exception handling is used with catch for ``std::bad_alloc`` or 32``std::exception``. At ``||``, ``&&``, ``,``, ``?`` (condition and one branch) 33operators no warning is emitted. No warning is emitted if both of the memory 34allocations are not assigned to a variable or not passed directly to a function. 35The reason is that in this case the memory may be intentionally not freed or the 36allocated 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 undefined 66 67 // List (aggregate) initialization is used. 68 C C1{new int, new int}; // no warning 69 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 undefined 72 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 exception 76 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 undefined 80 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 warning 84 85 X = (f2(new A) ? f1(new A) : f1(new B)); // no warning 86 87 // No warning if the result of both allocations is not passed to a function 88 // or stored in a variable. 89 (new A)->Var = (new B)->Var; // no warning 90 91 // No warning if at least one non-throwing allocation is used. 92 f(new(std::nothrow) A, new B); // no warning 93 } 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 warning 99 } 100