CertC++-STR50

Guarantee that storage for strings has sufficient space for character data and the null terminator

Required inputs: IR

Copying data to a buffer that is not large enough to hold that data results in a buffer overflow. Buffer overflows occur frequently when manipulating strings [ Seacord 2013]. To prevent such errors, either limit copies through truncation or, preferably, ensure that the destination is of sufficient size to hold the data to be copied. C-style strings require a null character to indicate the end of the string, while the C++ std::basic_string template requires no such character.

Noncompliant Code Example

Because the input is unbounded, the following code could lead to a buffer overflow.

#include <iostream>
 
void f() {
  char buf[12];
  std::cin >> buf;
}
Noncompliant Code Example

To solve this problem, it may be tempting to use the std::ios_base::width() method, but there still is a trap, as shown in this noncompliant code example.

#include <iostream>
 
void f() {
  char bufOne[12];
  char bufTwo[12];
  std::cin.width(12);
  std::cin >> bufOne;
  std::cin >> bufTwo;
}

In this example, the first read will not overflow, but could fill bufOne with a truncated string. Furthermore, the second read still could overflow bufTwo. The C++ Standard, [istream.extractors], paragraphs 7-9  [ ISO/IEC 14882-2014], describes the behavior of  operator>>(basic_istream &, charT *) and, in part, states the following:

operator>> then stores a null byte ( charT()) in the next position, which may be the first position if no characters were extracted.  operator>> then calls  width(0).

Consequently, it is necessary to call  width() prior to each  operator>> call passing a bounded array. However, this does not account for the input being truncated, which may lead to information loss or a possible vulnerability.

Compliant Solution

The best solution for ensuring that data is not truncated and for guarding against buffer overflows is to use  std::string instead of a bounded array, as in this compliant solution.

#include <iostream>
#include <string>
 
void f() {
  std::string input;
  std::string stringOne, stringTwo;
  std::cin >> stringOne >> stringTwo;
}
Noncompliant Code Example

In this noncompliant example, the unformatted input function  std::basic_istream<T>::read() is used to read an unformatted character array of 32 characters from the given file. However, the  read() function does not guarantee that the string will be null terminated, so the subsequent call of the  std::string constructor results in undefined behavior if the character array does not contain a null terminator.

#include <fstream>
#include <string>
 
void f(std::istream &in) {
  char buffer[32];
  try {
    in.read(buffer, sizeof(buffer));
  } catch (std::ios_base::failure &e) {
    // Handle error
  }

  std::string str(buffer);
  // ...
}
Compliant Solution

This compliant solution assumes that the input from the file is at most 32 characters. Instead of inserting a null terminator, it constructs the  std::string object based on the number of characters read from the input stream. If the size of the input is uncertain, it is better to use  std::basic_istream<T>::readsome() or a formatted input function, depending on need.

#include <fstream>
#include <string>

void f(std::istream &in) {
  char buffer[32];
  try {
    in.read(buffer, sizeof(buffer));
  } catch (std::ios_base::failure &e) {
    // Handle error
  }
  std::string str(buffer, in.gcount());
  // ...
}
Risk Assessment

Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code with the permissions of the vulnerable process.

Rule Severity Likelihood Remediation Cost Priority Level
STR50-CPP High Likely Medium P18 L1
Related Guidelines
SEI CERT C Coding Standard STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator
Bibliography
[ ISO/IEC 14882-2014] Subclause 27.7.2.2.3, " basic_istream::operator>>"
Subclause 27.7.2.3, "Unformatted Input Functions" 
[ Seacord 2013] Chapter 2, "Strings"
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/str50-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

non-null-termination

Do not pass a non-null-terminated character sequence to a library function that expects a string.

None

False

unbound_input_to_array

Ensure sufficient storage space for unbound input.

None

False

Options

excluded_arguments

excluded_arguments

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

Default:

{
   'snprintf': {0},
   'sprintf': {0},
   'strcpy': {0},
   'strncpy': {0},
   'strxfrm': {0},
   'vsprintf': {0},
   'wcscpy': {0},
   'wcsncpy': {0}
}
Arguments that should not be checked for entries in functions_under_test; first argument/parameter has index 0.
 

functions_under_test

functions_under_test : set[bauhaus.analysis.config.QualifiedName] = {'std::basic_string::basic_string'}

Functions which should not use non-null-terminated character sequences for their arguments. All arguments of type pointer to integral type (char, int, etc.) are checked. You can use excluded_arguments if you want to restrict the considered arguments.
 

use_static_semantic_analysis

use_static_semantic_analysis : bool = True

Whether the rule should use the results of the StaticSemanticAnalysis to check for non-null-terminated arguments. This can produce more findings, as additional appearances of unterminated character sequences are investigated, but can also remove false positives. This will not enforce StaticSemanticAnalysis to be enabled, but will not produce any additional results if it is not.