...
- Both iterators refer into the same container.
- The iterator representing the start of the range precedes the iterator representing the end of the range.
- The elements iterated over do not have unspecified values.The iterators are not invalidated, in conformance with CTR51-CPP. Use valid references, pointers, and iterators to reference elements of a container..
An empty iterator range (where the two iterators are valid and equivalent) is considered to be valid.
Using a range of Accessing two iterators that are invalidated or do not refer into the same container or accessing invalidated iterators results in undefined behavior.
Several generic standard template library (STL) algorithms, such as std::remove()
and std::unique()
, remove instances of elements from a container without shrinking the size of the container. Instead, these algorithms return a ForwardIterator
to indicate the partition within the container after which elements are no longer valid. The elements in the container that precede the returned iterator are valid elements with specified values, whereas the elements that succeed the returned iterator are valid but have unspecified values. Accessing unspecified values of elements iterated over results in unspecified behavior. Frequently, the erase-remove idiom is used to shrink the size of the container when using these algorithms.
Noncompliant Code Example
In this noncompliant example, the two iterators that delimit the range point into the same container, but the first iterator does not precede the second. On each iteration of its internal loop, std::for_each()
compares the first iterator (after incrementing it) with the second for equality, and as ; as long as they are not equal, it will continue to increment the first iterator. Incrementing the iterator representing the past-the-end element of the range results in undefined behavior.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> #include <iostream> #include <vector> void f(const std::vector<int> &Cc) { std::for_each(Cc.end(), Cc.begin(), [](int Ii) { std::cout << Ii; }); } |
Invalid iterator ranges can also result from comparison functions that return true for equal values. See CTR57-CPP. Provide a valid ordering predicate for more information about comparators.
...
In this compliant solution, the iterator values passed to std::for_each()
are passed in the proper order:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> #include <iostream> #include <vector> void f(const std::vector<int> &Cc) { std::for_each(Cc.begin(), Cc.end(), [](int Ii) { std::cout << Ii; }); } |
Noncompliant Code Example
In this noncompliant code example, iterators from different containers are passed for the same iterator range. Although many STL implementations will compile this code and exhibit reasonable behaviorthe program may behave as the developer expects, there is no requirement that an STL implementation treat a default-initialized iterator as a synonym for for the iterator returned by end()
.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> #include <iostream> #include <vector> void f(const std::vector<int> &Cc) { std::vector<int>::const_iterator Ee; std::for_each(Cc.begin(), Ee, [](int Ii) { std::cout << Ii; }); } |
Compliant Solution
In this compliant solution, the proper iterator generated by a call to end()
is passed:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> #include <iostream> #include <vector> void f(const std::vector<int> &Cc) { std::for_each(Cc.begin(), Cc.end(), [](int Ii) { std::cout << Ii; }); } |
Noncompliant Code Example
In this noncompliant code example, elements matching 42
are removed from the given container. The contents of the container are then printed to the standard output stream. However, if any elements were removed from the container, the range-based for
loop iterates over an invalid iterator range, resulting in unspecified behavior.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm>
#include <iostream>
#include <vector>
void f(std::vector<int> &C) {
std::remove(C.begin(), C.end(), 42);
for (auto V : C) {
std::cout << "Container element: " << V << std::endl;
}
} |
Compliant Solution
In this compliant solution, elements removed by the standard algorithm are subsequently erased from the given container. This technique ensures that a valid iterator range is used by the range-based for
loop.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm>
#include <iostream>
#include <vector>
void f(std::vector<int> &C) {
C.erase(std::remove(C.begin(), C.end(), 42), C.end());
for (auto V : C) {
std::cout << "Container element: " << V << std::endl;
}
} |
Risk Assessment
Using an invalid iterator range is similar to allowing a buffer overflow, which can lead to an attacker running arbitrary code.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CTR53-CPP | High | Probable | High | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|
Astrée |
| overflow_upon_dereference | |||||||
CodeSonar |
| LANG.MEM.BO | Buffer Overrun | ||||||
Helix QAC |
| C++3802 | |||||||
Parasoft C/C++test |
| CERT_CPP-CTR53-a | Do not use an iterator range that isn't really a range | ||||||
Polyspace Bug Finder |
| CERT C++: CTR53-CPP | Checks for invalid iterator range (rule partially covered). | ||||||
PVS-Studio |
| V539, V662, V789 |
Related Vulnerabilities
In fun Fun with erase(), Chris Rohlf discusses the exploit potential of a program that calls vector::erase()
with invalid iterator ranges [Rohlf 2009].
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | CTR51-CPP. Use valid references, pointers, and iterators to reference elements of a container CTR57-CPP. Provide a valid ordering predicate |
Bibliography
[ISO/IEC 14882-2014] | Clause 24, "Iterators Library" |
[Meyers |
2001] | Item 32, "Follow Remove- |
Like Algorithms with erase If You Really Want to Remove Something" |
...
...