Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

When using the nonthrowing form, it is imperative to check that the return value is not nullptr before accessing the resulting pointer. When using either form, be sure to comply with ERR30ERR50-CPP. Do not call std::terminate(), std::abort(), or std::_Exit().

Noncompliant Code Example

In this noncompliant code example, an array of int is created using ::operator new[](std::size_t), but the results of the allocation are not checked. Since the function is marked as noexcept, the caller assumes this function does not throw any exceptions. Because ::operator new[](std::size_t) can throw an exception if the allocation fails, this could lead to abnormal termination of the program.

Code Block
bgColor#FFcccc
langcpp
#include <cstring>
 
void f(const int *array, std::size_t size) noexcept {
  int *copy = new int[size];
  std::memcpy(copy, array, size * sizeof(*copy));
  // ...
  delete [] copy;
}

Compliant Solution (std::nothrow)

When using std::nothrow, the new operator returns either a null pointer or a pointer to the allocated space. Always test the returned pointer to ensure it is not nullptr before referencing the pointer. This compliant solution handles the error condition appropriately when the returned pointer is nullptr.

Code Block
bgColor#ccccff
langcpp
#include <cstring>
 
void f(const int *array, std::size_t size) noexcept {
  int *copy = new (std::nothrow) int[size];
  if (!copy) {
    // Handle error
    return;
  }
  std::memcpy(copy, array, size * sizeof(*copy));
  // ...
  delete [] copy;
}

Compliant Solution (std::bad_alloc)

Alternatively, one can use ::operator new[] without std::nothrow, and instead catch a std::bad_alloc exception if sufficient memory cannot be allocated.

Code Block
bgColor#ccccff
langcpp
#include <cstring>
 
void f(const int *array, std::size_t size) noexcept {
  int *copy;
  try {
    copy = new int[size];
  } catch(std::bad_alloc) {
    // Handle error
    return;
  }
  // At this point, copy has been initialized to allocated memory.
  std::memcpy(copy, array, size * sizeof(*copy));
  // ...
  delete [] copy;
}

Compliant Solution (noexcept(false))

If the design of the function is such that the caller is expected to handle exceptional situations, it is permissible to mark the function explicitly as one that may throw, as in this compliant solution. This is not strictly required, as any function without a noexcept specifier is presumed to allow throwing.

Code Block
bgColor#ccccff
langcpp
#include <cstring>
 
void f(const int *array, std::size_t size) noexcept(false) {
  int *copy = new int[size];
  // If the allocation fails, it will throw an exception which the caller
  // will have to handle.
  std::memcpy(copy, array, size * sizeof(*copy));
  // ...
  delete [] copy;
}

Noncompliant Code Example

In this noncompliant code example, two memory allocations are performed within the same expression. Because the memory allocations are passed as arguments to a function call, an exception thrown as a result of one of the calls to new could result in a memory leak.

...

Consider the situation where A is allocated and constructed first, and then B is allocated and throws an exception. Wrapping the call to g() in a try/catch block is insufficient because it would be impossible to free the memory allocated for A.

Compliant Solution (std::unique_ptr)

In this compliant solution, a std::unique_ptr is used to manage the resources for the A and B objects. In the situation described by the noncompliant code example, B throwing an exception would still result in the destruction and deallocation of the A object when then std::unique_ptr<A> was destroyed.

Code Block
bgColor#ccccff
langcpp
#include <memory>
 
struct A { /* ... */ };
struct B { /* ... */ }; 
 
void g(std::unique_ptr<A> a, std::unique_ptr<B> b);
void f() {
  g(std::make_unique<A>(), std::make_unique<B>());
}

Compliant Solution (References)

When possible, the more resilient compliant solution is to remove the memory allocation entirely, and pass the objects by reference instead:

Code Block
bgColor#ccccff
langcpp
struct A { /* ... */ };
struct B { /* ... */ }; 
 
void g(A &a, B &b);
void f() {
  A a;
  B b;
  g(a, b);
}

Risk Assessment

Failing to detect allocation failures can lead to abnormal program termination and denial-of-service attacks.

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MEM32-CPP

High

Likely

Medium

P18

L1

Automated Detection

Tool

Version

Checker

Description

 Compass/ROSE   
Coverity7.5CHECKED_RETURNFinds inconsistencies in how function call return values are handled.
Fortify SCA5.0  

Related Vulnerabilities

The vulnerability in Adobe Flash [VU#159523] arises because Flash neglects to check the return value from calloc(). Even though calloc() returns NULL, Flash does not attempt to read or write to the return value, but rather attempts to write to an offset from the return value. Dereferencing NULL usually results in a program crash, but dereferencing an offset from NULL allows an exploit to succeed without crashing the program.

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography

[ISO/IEC 14882-2014]

18.6.1.1, "Single-object Forms"
18.6.1.2, "Array Forms"
20.7.9.1, "Allocator Members"

[ISO/IEC 9899:2011]Section 7.20.3, "Memory management functions"
[Meyers 95]Item 7. Be prepared for out-of-memory conditions.
[Seacord 2013b]Chapter 4, "Dynamic Memory Management"

...