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::string,
std::wstring,
std::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] |
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
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
This rule has no individual options.