You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 37 Next »

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 2007van 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

Detectable

Repairable

Priority

Level

STR51-CPP

High

Likely

No

Yes

P18

L1

Automated Detection

Tool

Version

Checker

Description

Astrée

22.10

assert_failure

CodeSonar
9.1p0

LANG.MEM.NPD

Null Pointer Dereference

Helix QAC

2025.2

DF4770, DF4771, DF4772, DF4773, DF4774


Klocwork
2025.2

NPD.CHECK.CALL.MIGHT
NPD.CHECK.CALL.MUST
NPD.CHECK.MIGHT
NPD.CHECK.MUST
NPD.CONST.CALL
NPD.CONST.DEREF
NPD.FUNC.CALL.MIGHT
NPD.FUNC.CALL.MUST
NPD.FUNC.MIGHT
NPD.FUNC.MUST
NPD.GEN.CALL.MIGHT
NPD.GEN.CALL.MUST
NPD.GEN.MIGHT
NPD.GEN.MUST
RNPD.CALL
RNPD.DEREF


Parasoft C/C++test

2024.2

CERT_CPP-STR51-a

Avoid null pointer dereferencing

Polyspace Bug Finder

R2025b

CERT C++: STR51-CPPChecks for string operations on null pointer (rule partially covered).
Security Reviewer - Static Reviewer

This page was automatically generated and should not be edited.

The information on this page was provided by outside contributors and has not been verified by SEI CERT.

The table below can be re-ordered, by clicking column headers.

Tool Version: 6.02

Checker

Guideline

C01 CTR52-CPP. Guarantee that library functions do not overflow
C04 CTR52-CPP. Guarantee that library functions do not overflow
C17 FIO50-CPP. Do not alternately input and output from a file stream without an intervening positioning call
C24 STR52-CPP. Use valid references, pointers, and iterators to reference elements of a basic_string
C35 ERR51-CPP. Handle all exceptions
C53 EXP50-CPP. Do not depend on the order of evaluation for side effects
C54 EXP53-CPP. Do not read uninitialized memory
C55 EXP53-CPP. Do not read uninitialized memory
C56 EXP53-CPP. Do not read uninitialized memory
C57 EXP53-CPP. Do not read uninitialized memory
C58 EXP53-CPP. Do not read uninitialized memory
C59 EXP53-CPP. Do not read uninitialized memory
C60 EXP53-CPP. Do not read uninitialized memory
C61 EXP53-CPP. Do not read uninitialized memory
C62 EXP53-CPP. Do not read uninitialized memory
C63 EXP53-CPP. Do not read uninitialized memory
C80 FIO51-CPP. Close files when they are no longer needed
CPP_12 MEM50-CPP. Do not access freed memory
CPP_14 MEM50-CPP. Do not access freed memory
CPP_15 MEM50-CPP. Do not access freed memory
CPP_28 MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime
CPP_29 MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime
RTOS_07 MSC50-CPP. Do not use std::rand() for generating pseudorandom numbers
RTOS_08 MSC51-CPP. Ensure your random number generator is properly seeded
RTOS_09 MSC52-CPP. Value-returning functions must return a value from all exit paths
RTOS_10 MSC52-CPP. Value-returning functions must return a value from all exit paths
RTOS_11 MSC52-CPP. Value-returning functions must return a value from all exit paths
RTOS_12 MSC52-CPP. Value-returning functions must return a value from all exit paths
RTOS_33 STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator
RTOS_34 STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator
shadowVariable STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator
shiftTooManyBits STR51-CPP. Do not attempt to create a std::string from a null pointer
UNSAFE_03 STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator
UNSAFE_04 STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator
UNSAFE_07 OOP50-CPP. Do not invoke virtual functions from constructors or destructors
UNSAFE_08 CON53-CPP. Avoid deadlock by locking in a predefined order
UNSAFE_09 DCL50-CPP. Do not define a C-style variadic function
va_end_missing ERR59-CPP. Do not throw an exception across execution boundaries
va_start_subsequentCalls MEM56-CPP. Do not store an already-owned pointer value in an unrelated smart pointer
wcsdupCalled MEM51-CPP. Properly deallocate dynamically allocated resources

shiftTooManyBitsFully implemented

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

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]



  • No labels