Versions Compared

Key

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

When invoked by a new expression for a given type, the default global non-placement forms of operator new attempt to allocate sufficient storage for an object of the type and, if successful, return a pointer with alignment suitable for any object with a fundamental alignment requirement. However, the default placement new operator simply returns the given pointer back to the caller without guaranteeing that there is sufficient space in which to construct the object or ensuring that the pointer meets the proper alignment requirements. The C++ Standard, [expr.new], paragraph 16 [ISO/IEC 14882-2014], nonnormatively states the following:

[Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size. The address of the created object will not necessarily be the same as that of the block if the object is an array. —end note]

(This note is a reminder of the general requirements specified by the C++ Standard, [basic.stc.dynamic.allocation], paragraph 1, which apply to placement new operators by virtue of [basic.stc.dynamic], paragraph 3.)

In addition, the standard provides the following example later in the same section:

new(2, f) T[5] results in a call of operator new[](sizeof(T) * 5 + y, 2, f).

Here, ... and y are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by operator new[]. This overhead may be applied in all array new-expressions, including those referencing the library function operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.

Do not pass a pointer that is not suitably aligned for the object being constructed to placement new. Doing so results in an object being constructed at a misaligned location, which results in undefined behavior. Do not pass a pointer that has insufficient storage capacity for the object being constructed, including the overhead required for arrays. Doing so may result in initialization of memory outside of the bounds of the object being constructed, which results in undefined behavior. 

Finally, do not use placement new[] on any platform that does not specify a limit for the overhead it requires.

Noncompliant Code Example

In this noncompliant code example, a pointer to a short is passed to placement new, which is attempting to initialize a long. On architectures where sizeof(short) < sizeof(long), this results in undefined behavior. This example, and subsequent ones, all assume the pointer returned by placement new will not be used after the lifetime of its underlying storage has ended. For instance, the pointer will not be stored in a static global variable and dereferenced after the call to f() has ended. This assumption is in conformance with MEM50-CPP. Do not access freed memory

The placement new operator enables the programmer to specify the memory in which an object being constructed will be located. A problem may arise if a pointer to this memory is misaligned with the platform's underlying architecture alignment restrictions. On several RISC architectures, such as PowerPC or IA64 (Itanium), access to misaligned objects might cause the program to terminate abnormally. This can also occur on IA32 CPUs which have been configured to fault on misaligned access.

Noncompliant Code Example

In this noncompliant code, a struct of type A is allocated on the memory region of s.B. The problem is that A has a member of type unsigned long which, on IA32 systems, is required to be aligned to 4. However, B is an array of unsigned chars inside S and is not aligned to 4. After the call to operator new, the pointer a is pointing to an unaligned memory address. Writing val into a->i can cause the program to terminate abnormally.

Code Block
bgColor#FFcccc
langcpp

struct A#include <new>
 
void f() {
  short s;
 unsigned long *lp = ::new (&s) long;
}

Noncompliant Code Example

This noncompliant code example ensures that the long is constructed into a buffer of sufficient size. However, it does not ensure that the alignment requirements are met for the pointer passed into placement new. To make this example clearer, an additional local variable c has also been declared.

Code Block
bgColor#FFcccc
langcpp
#include <new>
 
void f()i;
};

struct S {
  unsigned char x;c; // Used elsewhere in the function
  unsigned char Bbuffer[sizeof(Along)];
} s;


int main() {
long  A *alp = ::new(&s.B[0]) A;
  unsigned long val = 0xaabbccdd;
  a->i = val;
  return 0;
}
 (buffer) long;
 
  // ...
}

Compliant Solution (

...

alignas)

In the following this compliant solution, a union the alignas declaration specifier is used to impose the alignment of unsigned long on the array Bensure the buffer is appropriately aligned for a long.

Code Block
bgColor#ccccff
langcpp

struct A#include <new>
 
void f() {
  char c; // unsignedUsed long i;
};

union AlignedUnion {
 elsewhere in the function
  alignas(long) unsigned char Bbuffer[sizeof(Along)];

private:  long *lp = ::new (buffer) long;
 
  unsigned long _align_;
} algn;

int main// ...
}

Compliant Solution (std::aligned_storage)

This compliant solution ensures that the long is constructed into a buffer of sufficient size and with suitable alignment.

Code Block
bgColor#ccccff
langcpp
#include <new>
 
void f() {
  char c; // Used elsewhere in the Afunction
 *a = new(&algn.B[0]) A std::aligned_storage<sizeof(long), alignof(long)>::type buffer;
  unsigned long val*lp = 0xaabbccdd;
  a->i = val;::new (&buffer) long;
 
  return (0);// ...
}

Compliant Solution (G++)

Noncompliant Code Example (Failure to Account for Array Overhead)

This noncompliant code example attempts to allocate sufficient storage of the appropriate alignment for the array of objects of S.  However, it fails to account for the overhead an implementation may add to the amount of storage for array objects.  The overhead (commonly referred to as a cookie) is necessary to store the number of elements in the array so that the array delete expression or the exception unwinding mechanism can invoke the type's destructor on each successfully constructed element of the array.  While some implementations are able to avoid allocating space for the cookie in some situations, assuming they do in all cases is unsafeThe following is a compliant solution on a IA32 system using g++. In this solution, the ALIGN macro was added to ensure alignment when compiling with g++. In this case, it is used on B to make it aligned to 4, which is the alignment restriction for unsigned long.

Code Block
bgColor#ccccff#FFcccc
langcpp

#define ALIGN(X) __attribute__((aligned(X)))


struct A#include <new>

struct S {
  S ();
 unsigned long~S i();
};

structvoid Sf() {
  const unsigned N char= x32;
  ALIGNalignas(4S) unsigned char Bbuffer[sizeof(AS) * N];
} s;


int main() {
  A *a = new(&s.B[0]) A;
  unsigned long val = 0xaabbccdd;
  a->i = val;
  return 0;
}

Compliant Solution (MSVC)

  S *sp = ::new (buffer) S[N];
 
  // ...
  // Destroy elements of the array.
  for (size_t i = 0; i != n; ++i) {
    sp[i].~S();
  }
}

Compliant Solution (Clang/GCC)

The amount of overhead required by array new expressions is unspecified but ideally would be documented by quality implementations. The following compliant solution is specifically for the Clang and GNU GCC compilers, which guarantee that the overhead for dynamic array allocations is a single value of type size_t. (Note that this value is often treated as a "-1th" element in the array, so the actual space used may be larger.) To verify that the assumption is, in fact, safe, the compliant solution also overloads the placement new[] operator to accept the buffer size as a third argument and verifies that it is not smaller than the total amount of storage requiredThe following is a compliant solution on a IA32 system using Microsoft Visual Studio. In this solution, the ALIGN macro was added to ensure alignment when compiling with Microsoft VS. The ALIGN() macro calls either declspec(align()) or attribute_((aligned())) to enforce alignment on a particular variable. In this case, it is used on B to make it aligned to 4, which is the alignment restriction for unsigned long.

Code Block
bgColor#ccccff
langcpp

#define ALIGN(X) _declspec(align(X))


struct A {
  unsigned long i;
};

struct S {
  unsigned char x;
  ALIGN(4) unsigned char B[sizeof(A)];
} s;


int main() {
  A *a = new(&s.B[0]) A;
  unsigned long val = 0xaabbccdd;
  a->i = val;
  return 0;
}

Risk Assessment

#include <cstddef>
#include <new>

#if defined(__clang__) || defined(__GNUG__)
  const size_t overhead = sizeof(size_t);
#else
  static_assert(false, "you need to determine the size of your implementation's array overhead");
  const size_t overhead = 0; // Declaration prevents additional diagnostics about overhead being undefined; the value used does not matter.
#endif

struct S {
  S();
  ~S();
};

void *operator new[](size_t n, void *p, size_t bufsize) {
  if (n > bufsize) {
    throw std::bad_array_new_length();
  }
  return p;
}

void f() {
  const size_t n = 32;
  alignas(S) unsigned char buffer[sizeof(S) * n + std::max(overhead, alignof(S))];
  S *sp = ::new (buffer, sizeof(buffer)) S[n];
 
  // ...
  // Destroy elements of the array.
  for (size_t i = 0; i != n; ++i) {
    sp[i].~S();
  }
}

Porting this compliant solution to other implementations requires adding similar conditional definitions of the overhead constant, depending on the constraints of the platform.

Risk Assessment

Passing improperly aligned pointers or pointers to insufficient storage to placement new expressions can result in undefined behavior, including buffer overflow and abnormal termination.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MEM45-CPP

low

probable

low

P6

L2

MEM54-CPP

High

Likely

Medium

P18

L1

Automated Detection

Tool

Version

Checker

Description

Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC++-MEM54
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.MEM.BO

Buffer Overrun

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C++3119, C++3128, DF3520, DF3521, DF3522, DF3523


LDRA tool suite
Include Page
LDRA_V
LDRA_V

597 S

Enhanced Enforcement

Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_CPP-MEM54-a
CERT_CPP-MEM54-b

Do not pass a pointer that has insufficient storage capacity or that is not suitably aligned for the object being constructed to placement 'new'
An overhead should be used when an array of objects is passed to the placement 'new' allocation function

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: MEM54-CPPChecks for placement new used with insufficient storage or misaligned pointers (rule fully covered)
PVS-Studio

Include Page
PVS-Studio_V
PVS-Studio_V

V752

Related Vulnerabilities

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

Related Guidelines

Bibliography

...

...

Subclause 3.7.4, "Dynamic Storage Duration"
Subclause 5.3.4, "New" 


...

Image Added Image Added Image Added .1