Versions Compared

Key

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

...

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
bgColor#FFcccc
langcpp
#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
bgColor#ccccff
langcpp
#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
bgColor#ccccff
langcpp
#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
bgColor#ffcccc
langcpp
#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
bgColor#ccccff
langcpp
#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

Bibliography

[ISO/IEC 14882-2014]

23, "Containers Library"
24.2.1, "In General" 

[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

...