int *intArray = new int[20]; // memory is allocated
// elements of intArray can be written or read here
delete[] intArray; // memory is released
intArray[3] = 10; // Noncompliant: memory is used after it was released
----
Releasing a memory block by invoking `free` or operator `delete`
informs the memory management system that the program no longer uses the given block.
Depending on the state and load of the program, such block can be then:
* reused, i.e., the allocation function returns the same pointer,
* released to the operating system, making it inaccessible to the program.
=== What is the potential impact?
Accessing released memory causes undefined behavior.
This means the compiler is not bound by the language standard anymore, and your program has no meaning assigned to it.
Practically this has a wide range of effects:
* The program may crash due to the memory no longer being accessible,
or due to unexpected value being read or written via the pointer.
* Reading from the released memory may produce a garbage value.
* When the memory was already reused to store sensitive data, such as passwords, it may lead to a vulnerability that uses this defect to extract information from an instance of the program.
* Writing to released memory may change the value of the unrelated object in a remote part of the code if the memory was reused by it.
As different objects may reuse same the block of memory between runs, this leads to unintuitive and hard diagnose bugs.
== How to fix it
In most situations, the use of an uninitialized object is a strong indication of a defect in the code,
and fixing it requires a review of the object allocation and deallocation strategies.
Generally, the fix requires adjusting the code, so either:
* Moving accesses to the memory before the deallocation
* Moving the deallocation so it happens after all the uses
If possible, it is desired to remove manual memory allocation,
and replace it with stack-allocated objects, or in the case of {cpp},
stack objects that manage memory (using RAII idiom).
This guarantees that accessing a memory managed by such an object is not released as long as such an object is not modified or destroyed (some _RAII_ types provide a stronger guarantee).
[source,cpp]
----
std::vector<int> intArray(10); // manages an array of 10 integers, on the heap
std::unique_ptr<Class> objPtr = std::make_unique<Class>(); // manages an object on the heap
intArray[5]; // OK
objPtr->foo(); // OK
----
However, any raw pointers or references to memory held by _RAII_ object may still lead to a use after free:
[source,cpp]
----
int* p1 = &intArray[0]; // becomes dangling when intArray is destroyed
int* p2 = intArray.data(); // same as above
Class* p3 = objPtr.get(); // becomes dangling, when objPtr releases the pointer