...
A std::basic_string
object is also a container for which this rule applies. For more specific information pertaining to std::basic_string
containers, see STR38STR52-CPP. Use valid references, pointers, and iterators to reference elements of a basic_string.
Noncompliant Code Example
In this noncompliant code example, pos
is invalidated after the call to insert()
, and subsequent loop iterations have undefined behavior:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <deque> void f(const double *items, std::size_t count) { std::deque<double> d; auto pos = d.begin(); for (std::size_t i = 0; i < count; ++i, ++pos) { d.insert(pos, items[i] + 41.0); } } |
Compliant Solution (Updated Iterator)
In this compliant solution, pos
is assigned a valid iterator on each insertion, removing the undefined behavior:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <deque> void f(const double *items, std::size_t count) { std::deque<double> d; auto pos = d.begin(); for (std::size_t i = 0; i < count; ++i, ++pos) { pos = d.insert(pos, items[i] + 41.0); } } |
Compliant Solution (Generic Algorithm)
This compliant solution replaces the hand-written loop with the generic STL algorithm std::transform
. The call to std::transform
accepts the range of elements to transform, the location of where to store the transformed values (which, in this case, is a std::inserter
object to insert them at the beginning of d
), and the transformation function to apply (which, in this case, is a simple lambda).
Code Block | ||||
---|---|---|---|---|
| ||||
#include <deque> #include <algorithm> #include <iterator> void f(const double *items, std::size_t count) { std::deque<double> d; std::transform(items, items + count, std::inserter(d, d.begin()), [](double d) { return d + 41.0; }); } |
Noncompliant Code Example
In this noncompliant code example, data
is invalidated after the call to replace()
, and so its use in g()
is undefined behavior:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> #include <string> extern void g(const char *); void f(std::string &example_string) { const char *data = example_string.data(); // ... example_string.replace(0, 2, "bb"); // ... g(data); } |
Compliant Solution
In this compliant solution, the pointer to example_string
's internal buffer is not generated until after the modifications from replace()
have completed:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> #include <string> extern void g(const char *); void f(std::string &example_string) { // ... example_string.replace(0, 2, "bb"); // ... g(example_string.data()); } |
Risk Assessment
Using invalid references, pointers, or iterators to reference elements of a container results in undefined behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CTR32-CPP | High | Probable | High | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Coding Standard | STR38STR52-CPP. Use valid references, pointers, and iterators to reference elements of a basic_string |
Bibliography
[ISO/IEC 14882-2014] | 23, "Containers Library" |
[Meyers 01] | Item 43: Prefer algorithm calls to hand-written loops |
[Sutter 04] | Item 84: Prefer algorithm calls to handwritten loops |
[Kalev 99] | ANSI/ISO C++ Professional Programmer's Handbook |
...