CertC++-STR52

Use valid references, pointers, and iterators to reference elements of a basic_string

Required inputs: IR

Since  std::basic_string is a container of characters, this rule is a specific instance of  CTR51-CPP. Use valid references, pointers, and iterators to reference elements of a container. As a container, it supports iterators just like other containers in the Standard Template Library. However, the std::basic_string template class has unusual invalidation semantics. The C++ Standard, [string.require], paragraph 5 [ ISO/IEC 14882-2014], states the following:

References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object:

  • As an argument to any standard library function taking a reference to non-const basic_string as an argument.
  • Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and  rend.

Examples of standard library functions taking a reference to non- const std::basic_string are std::swap(), ::operator>>(basic_istream &, string &), and std::getline().

Do not use an invalidated reference, pointer, or iterator because doing so results in undefined behavior.

Noncompliant Code Example

This noncompliant code example copies  input into a std::string, replacing semicolon ( ;) characters with spaces. This example is noncompliant because the iterator loc is invalidated after the first call to insert(). The behavior of subsequent calls to insert() is undefined.

#include <string>
 
void f(const std::string &input) {
  std::string email;

  // Copy input into email converting ";" to " "
  std::string::iterator loc = email.begin();
  for (auto i = input.begin(), e = input.end(); i != e; ++i, ++loc) {
    email.insert(loc, *i != ';' ? *i : ' ');
  }
}
Compliant Solution ( std::string::insert())

In this compliant solution, the value of the iterator loc is updated as a result of each call to insert() so that the invalidated iterator is never accessed. The updated iterator is then incremented at the end of the loop.

#include <string>

void f(const std::string &input) {
  std::string email;

  // Copy input into email converting ";" to " "
  std::string::iterator loc = email.begin();
  for (auto i = input.begin(), e = input.end(); i != e; ++i, ++loc) {
    loc = email.insert(loc, *i != ';' ? *i : ' ');
  }
}
Compliant Solution ( std::replace())

This compliant solution uses a standard algorithm to perform the replacement. When possible, using a generic algorithm is preferable to inventing your own solution.

#include <algorithm>
#include <string>

void f(const std::string &input) {
  std::string email{input};
  std::replace(email.begin(), email.end(), ';', ' ');
}
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.

#include <iostream>
#include <string>
 
extern void g(const char *);
 
void f(std::string &exampleString) {
  const char *data = exampleString.data();
  // ...
  exampleString.replace(0, 2, "bb");
  // ...
  g(data);
}
Compliant Solution

In this compliant solution, the pointer to  exampleString's internal buffer is not generated until after the modification from  replace() has completed.

#include <iostream>
#include <string>

extern void g(const char *);

void f(std::string &exampleString) {
  // ...
  exampleString.replace(0, 2, "bb");
  // ...
  g(exampleString.data());
}
Risk Assessment

Using an invalid reference, pointer, or iterator to a string object could allow an attacker to run arbitrary code.

Rule Severity Likelihood Remediation Cost Priority Level
STR52-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
Bibliography
[ ISO/IEC 14882-2014] Subclause 21.4.1, " basic_string General Requirements"
[ Meyers 2001] Item 43, "Prefer Algorithm Calls to Hand-written Loops"
Excerpt from SEI CERT C++ Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-cpp-coding-standard/rules/characters-and-strings-str/str52-cpp], Copyright (C) 1995-2026 Carnegie Mellon University. See section 9.4. "3rd-Party Licenses" in the documentation for full details.

Possible Messages

Key

Text

Severity

Disabled

invalidated_object

The referenced object “{}” of {} “{}” could be invalid.

None

False

Options

invalidating_function_map

invalidating_function_map

Type: dict[bauhaus.analysis.config.QualifiedName, set[bauhaus.analysis.config.FunctionName]]

Default:

{
   'std::basic_string': set()
}
Invalidating (unqualified) methods for the given (qualified) container types. (Some method names may come from super classes of the container type.) If an empty set of invalidating functions is given for a certain type (i.e. 'std::basic_string'), all methods not explicitly given in the option 'non_invalidating_functions' are considered as invalidating.
 

invalidating_only_argument_map

invalidating_only_argument_map

Type: dict[bauhaus.analysis.config.QualifiedName, set[bauhaus.analysis.config.FunctionName]]

Default:

{
   'std::list': {'erase'},
   'std::map': {'erase'},
   'std::multimap': {'erase'},
   'std::multiset': {'erase'},
   'std::set': {'erase'},
   'std::unordered_map': {'erase'},
   'std::unordered_multimap': {'erase'},
   'std::unordered_multiset': {'erase'},
   'std::unordered_set': {'erase'}
}
For functions like "erase" only taking a single iterator argument only this argument iterator is invalided (possibly missing aliases). This avoids false positives for a common pattern where elements are erased in a loop.
 

non_invalidating_functions

non_invalidating_functions : set[bauhaus.analysis.config.FunctionName] = {'at', 'back', 'begin', 'end', 'front', 'operator[]', 'rbegin', 'rend'}

Non-invalidating methods for all container types.