Versions Compared

Key

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

...

It is at the memory manager's discretion when to reallocate or recycle the freed memory. When memory is freed, all pointers into it become invalid, and its contents might either be returned to the operating system, making the freed space inaccessible, or remain intact and accessible. As a result, the data at the freed location can appear to be valid but change unexpectedly. Consequently, memory must not be written to or read from once it is freed.

Page properties
hiddentrue

This rule could probably stand to cover memory which has yet to be allocated. For instance:

Code Block
void f() {
  unsigned char *ptr;
  *ptr = 0;
}

This isn't really covered by EXP53-CPP. Do not read uninitialized memory because it has nothing to do with reading an unitialized value.

Noncompliant Code Example (new and delete)

...

Code Block
bgColor#ccccff
langcpp
#include <string>
 
std::string someStringReturningFunction();
void displayString(const char *s);

void f() {
  std::string str = someStringReturningFunction();
  const char *str = str.c_str();
  displayString(str);  /* ok */
}

Noncompliant Code Example

In this noncompliant code example, an attempt is made to allocate zero bytes of memory through a call to operator new(). If this request succeeds, operator new() is required to return a nonnull pointer value. However, according to the C++ Standard, [basic.stc.dynamic.allocation], paragraph 2 [ISO/IEC 14882-2014], attempting to indirect through such a pointer results in undefined behavior.

Code Block
bgColor#FFcccc
langcpp
#include <new>

void f() noexcept(false) {
  unsigned char *ptr = static_cast<unsigned char *>(::operator new(0));
  *ptr = 0;
  // ...
  ::operator delete(ptr);
}

Compliant Solution

The compliant solution depends on programmer intent. If the programmer intended to allocate a single unsigned char object, the compliant solution is to use new instead of a direct call to operator new(), as this compliant solution demonstrates:

Code Block
bgColor#ccccff
langcpp
void f() noexcept(false) {
  unsigned char *ptr = new unsigned char;
  *ptr = 0;
  // ...
  delete ptr;
}

If the programmer intended to allocate zero bytes of memory (perhaps in order to obtain a unique pointer value that cannot be reused by any other pointer in the program, until it is properly released), then the compliant solution is to not attempt to dereference the resulting pointer. Instead, ptr is declared as a void *, which cannot be indirected through in a conforming implementation.

Code Block
bgColor#ccccff
langcpp
#include <new>

void f() noexcept(false) {
  void *ptr = ::operator new(0);
  // ...
  ::operator delete(ptr);
}

Risk Assessment

Reading previously dynamically allocated memory after it has been deallocated can lead to abnormal program termination and denial-of-service attacks. Writing memory that has been deallocated can lead to the execution of arbitrary code with the permissions of the vulnerable process.

...

Bibliography

[ISO/IEC 14882-2014]3.7.4.1, "Allocation Functions"
3.7.4.2, "Deallocation Functions" 
[Seacord 2013b]Chapter 4, "Dynamic Memory Management"

...