CertC++-STR51ΒΆ

Do not attempt to create a std::string from a null pointer

Required inputs: IR, StaticSemanticAnalysis

The  std::basic_string type uses the traits design pattern to handle implementation details of the various string types, resulting in a series of string-like classes with a common, underlying implementation. Specifically, the  std::basic_string class is paired with  std::char_traits to create the  std::stringstd::wstringstd::u16string, and  std::u32string classes. The  std::char_traits class is explicitly specialized to provide policy-based implementation details to the  std::basic_string type. One such implementation detail is the  std::char_traits::length() function, which is frequently used to determine the number of characters in a null-terminated string. According to the C++ Standard, [char.traits.require], Table 62 [ ISO/IEC 14882-2014], passing a null pointer to this function is  undefined behavior because it would result in dereferencing a null pointer.

The following  std::basic_string member functions result in a call to  std::char_traits::length():

  • basic_string::basic_string(const charT *, const Allocator &)
  • basic_string &basic_string::append(const charT *) 
  • basic_string &basic_string::assign(const charT *)
  • basic_string &basic_string::insert(size_type, const charT *)
  • basic_string &basic_string::replace(size_type, size_type, const charT *)
  • basic_string &basic_string::replace(const_iterator, const_iterator, const charT *)
  • size_type basic_string::find(const charT *, size_type)
  • size_type basic_string::rfind(const charT *, size_type)
  • size_type basic_string::find_first_of(const charT *, size_type)
  • size_type basic_string::find_last_of(const charT *, size_type)
  • size_type basic_string::find_first_not_of(const charT *, size_type)
  • size_type basic_string::find_last_not_of(const charT *, size_type)
  • int basic_string::compare(const charT *)
  • int basic_string::compare(size_type, size_type, const charT *)
  • basic_string &basic_string::operator=(const charT *)
  • basic_string &basic_string::operator+=(const charT *)

The following  std::basic_string nonmember functions result in a call to to  std::char_traits::length():

  • basic_string operator+(const charT *, const basic_string&)
  • basic_string operator+(const charT *, basic_string &&)
  • basic_string operator+(const basic_string &, const charT *)
  • basic_string operator+(basic_string &&, const charT *)
  • bool operator==(const charT *, const basic_string &)
  • bool operator==(const basic_string &, const charT *)
  • bool operator!=(const charT *, const basic_string &)
  • bool operator!=(const basic_string &, const charT *)
  • bool operator<(const charT *, const basic_string &)
  • bool operator<(const basic_string &, const charT *)
  • bool operator>(const charT *, const basic_string &)
  • bool operator>(const basic_string &, const charT *)
  • bool operator<=(const charT *, const basic_string &)
  • bool operator<=(const basic_string &, const charT *)
  • bool operator>=(const charT *, const basic_string &)
  • bool operator>=(const basic_string &, const charT *)

Do not call any of the preceding functions with a null pointer as the  const charT * argument.

This rule is a specific instance of  EXP34-C. Do not dereference null pointers.

Implementation Details

Some standard library vendors, such as libstdc++,throw a  std::logic_error when a null pointer is used in the above function calls, though not when calling std::char_traits::length(). However, std::logic_error is not a requirement of the C++ Standard, and some vendors (e.g., libc++ and the Microsoft Visual Studio STL) do not implement this behavior. For portability, you should not rely on this behavior.

Noncompliant Code Example

In this noncompliant code example, a  std::string object is created from the results of a call to  std::getenv(). However, because std::getenv() returns a null pointer on failure, this code can lead to undefined behavior when the environment variable does not exist (or some other error occurs).

#include <cstdlib>
#include <string>
 
void f() {
  std::string tmp(std::getenv("TMP"));
  if (!tmp.empty()) {
    // ...
  }
}
Compliant Solution

In this compliant solution, the results from the call to  std::getenv() are checked for null before the  std::string object is constructed.

#include <cstdlib>
#include <string>

void f() {
  const char *tmpPtrVal = std::getenv("TMP");
  std::string tmp(tmpPtrVal ? tmpPtrVal : "");
  if (!tmp.empty()) {
    // ...
  }
}
Risk Assessment

Dereferencing a null pointer is undefined behavior, typically  abnormal program termination. In some situations, however, dereferencing a null pointer can lead to the execution of arbitrary code [ Jack 2007,  van Sprundel 2006]. The indicated severity is for this more severe case; on platforms where it is not possible to exploit a null pointer dereference to execute arbitrary code, the actual severity is low.

Rule Severity Likelihood Remediation Cost Priority Level
STR51-CPP High Likely Medium P18 L1
Related Guidelines
SEI CERT C Coding Standard EXP34-C. Do not dereference null pointers
Bibliography
[ ISO/IEC 9899:2011] Subclause 7.20.3, "Memory Management Functions"
[ ISO/IEC 14882-2014] Subclause 21.2.1, "Character Trait Requirements"
[ Jack 2007]
[ van Sprundel 2006]
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/string-from-a-null-pointer], 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

possible_std_string_from_nullptr

Argument might be null.

None

False

std_string_from_nullptr

Argument is null.

None

False

Options