CertC++-CTR53¶
Use valid iterator ranges
Required inputs: IR
When iterating over elements of a container, the iterators used must iterate over a valid range. An iterator range is a pair of iterators that refer to the first and past-the-end elements of the range respectively.
A valid iterator range has all of the following characteristics:
- 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 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 two iterators that are invalidated or do not refer into the same container results in undefined behavior.
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; 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.
#include <algorithm>
#include <iostream>
#include <vector>
void f(const std::vector<int> &c) {
std::for_each(c.end(), c.begin(), [](int i) { std::cout << i; });
}
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.
Compliant Solution
In this compliant solution, the iterator values passed to
std::for_each() are passed in the proper order.
#include <algorithm>
#include <iostream>
#include <vector>
void f(const std::vector<int> &c) {
std::for_each(c.begin(), c.end(), [](int i) { std::cout << i; });
}
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 the program may behave as the developer expects,
there is no requirement that an STL implementation treat a default-initialized
iterator as a synonym for the iterator returned by
end().
#include <algorithm>
#include <iostream>
#include <vector>
void f(const std::vector<int> &c) {
std::vector<int>::const_iterator e;
std::for_each(c.begin(), e, [](int i) { std::cout << i; });
}
Compliant Solution
In this compliant solution, the proper iterator generated by a call to
end() is passed.
#include <algorithm>
#include <iostream>
#include <vector>
void f(const std::vector<int> &c) {
std::for_each(c.begin(), c.end(), [](int i) { std::cout << i; });
}
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 |
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" Subclause 25.3, "Mutating Sequence Operations" |
| [ Meyers 2001] | Item 32, "Follow Remove-Like Algorithms with
erase If You Really Want to Remove Something"
|
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
different_iterators_containers |
Iterators for parameter ‘{}’ and parameter ‘{}’ come from different containers. |
None |
False |
iterator_might_not_initialized |
Not all paths initialize iterator ‘{}’ for parameter ‘{}’. |
None |
False |
iterator_not_initialized |
Iterator ‘{}’ for parameter ‘{}’ is not initialized. |
None |
False |
possible_different_iterators_containers |
Iterators for parameter ‘{}’ and parameter ‘{}’ come possibly from different containers. |
None |
False |
possible_reversed_iterators |
Possibly invalid {} for parameter ‘{}’. |
None |
False |
reversed_iterators |
Invalid {} for parameter ‘{}’. |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
begin_parameter_member_function_names¶
begin_parameter_member_function_names : set[str] = {'begin', 'cbegin', 'constBegin', 'crbegin', 'rbegin'}
end_parameter_member_function_names¶
end_parameter_member_function_names : set[str] = {'cend', 'constEnd', 'crend', 'end', 'rend'}
functions¶
functions
Table of functions with unchecked output iterator(s).Type: dict[bauhaus.analysis.config.QualifiedName, tuple]
Default:
{ 'std::copy': (0, 1), 'std::copy_backwards': (0, 1), 'std::copy_if': (0, 1), 'std::for_each': (0, 1), 'std::move': (0, 1), 'std::move_backward': (0, 1), 'std::partition_copy': (0, 1), 'std::remove_copy': (0, 1), 'std::remove_copy_if': (0, 1), 'std::replace_copy': (0, 1), 'std::replace_copy_if': (0, 1), 'std::rotate_copy': (0, 2), 'std::transform': (0, 1), 'std::unique_copy': (0, 1), 'std::vector::insert': (2, 3) }