CertC++-DCL58

Do not modify the standard namespaces

Required inputs: IR

Namespaces introduce new declarative regions for declarations, reducing the likelihood of conflicting identifiers with other declarative regions. One feature of namespaces is that they can be further extended, even within separate translation units. For instance, the following declarations are well-formed.

namespace MyNamespace {
int length;
}
 
namespace MyNamespace {
int width;
}
 
void f() {
  MyNamespace::length = MyNamespace::width = 12;
}

The standard library introduces the namespace  std for standards-provided declarations such as  std::stringstd::vector, and  std::for_each. However, it is undefined behavior to introduce new declarations in namespace  std except under special circumstances. The C++ Standard, [namespace.std], paragraphs 1 and 2 [ ISO/IEC 14882-2014], states the following:

1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

2 The behavior of a C++ program is undefined if it declares

- an explicit specialization of any member function of a standard library class template, or
- an explicit specialization of any member function template of a standard library class or class template, or
- an explicit or partial specialization of any member class template of a standard library class or class template.

In addition to restricting extensions to the the namespace  std, the C++ Standard, [namespace.posix], paragraph 1, further states the following:

The behavior of a C++ program is undefined if it adds declarations or definitions to namespace posix or to a namespace within namespace posix unless otherwise specified. The namespace posix is reserved for use by ISO/IEC 9945 and other POSIX standards.

Do not add declarations or definitions to the standard namespaces  std or  posix, or to a namespace contained therein, except for a template specialization that depends on a user-defined type that meets the standard library requirements for the original template.

The Library Working Group, responsible for the wording of the Standard Library section of the C++ Standard, has an unresolved issue on the definition of user-defined type. Although the Library Working Group has no official stance on the definition [ INCITS 2014], we define it to be any  classstructunion, or  enum that is not defined within namespace  std or a namespace contained within namespace std. Effectively, it is a user-provided type instead of a standard library-provided type.

Noncompliant Code Example

In this noncompliant code example, the declaration of  x is added to the namespace  std, resulting in undefined behavior.

namespace std {
int x;
}
Compliant Solution

This compliant solution assumes the intention of the programmer was to place the declaration of  x into a namespace to prevent collisions with other global identifiers. Instead of placing the declaration into the namespace  std, the declaration is placed into a namespace without a reserved name.

namespace nonstd {
int x;
}
Noncompliant Code Example

In this noncompliant code example, a template specialization of  std::plus is added to the namespace  std in an attempt to allow  std::plus to concatenate a  std::string and  MyString object. However, because the template specialization is of a standard library-provided type ( std::string), this code results in undefined behavior.

#include <functional>
#include <iostream>
#include <string>

class MyString {
  std::string data;

public:
  MyString(const std::string &data) : data(data) {}

  const std::string &get_data() const { return data; }
};

namespace std {
template <>
struct plus<string> : binary_function<string, MyString, string> {
  string operator()(const string &lhs, const MyString &rhs) const {
    return lhs + rhs.get_data();
  }
};
}

void f() {
  std::string s1("My String");
  MyString s2(" + Your String");
  std::plus<std::string> p;

  std::cout << p(s1, s2) << std::endl;
}
Compliant Solution

The interface for  std::plus requires that both arguments to the function call operator and the return type are of the same type. Because the attempted specialization in the noncompliant code example results in undefined behavior, this compliant solution defines a new  std::binary_function derivative that can add a  std::string to a  MyString object without requiring modification of the namespace  std.

#include <functional>
#include <iostream>
#include <string>

class MyString {
  std::string data;

public:
  MyString(const std::string &data) : data(data) {}

  const std::string &get_data() const { return data; }
};

struct my_plus : std::binary_function<std::string, MyString, std::string> {
  std::string operator()(const std::string &lhs, const MyString &rhs) const {
    return lhs + rhs.get_data();
  }
};

void f() {
  std::string s1("My String");
  MyString s2(" + Your String");
  my_plus p;

  std::cout << p(s1, s2) << std::endl;
}
Compliant Solution

In this compliant solution, a specialization of std::plus is added to the  std namespace, but the specialization depends on a user-defined type and meets the Standard Template Library requirements for the original template, so it complies with this rule. However, because  MyString can be constructed from  std::string, this compliant solution involves invoking a converting constructor whereas the previous compliant solution does not.

#include <functional>
#include <iostream>
#include <string>

class MyString {
  std::string data;

public:
  MyString(const std::string &data) : data(data) {}

  const std::string &get_data() const { return data; }
};

namespace std {
template <>
struct plus<MyString> {
  MyString operator()(const MyString &lhs, const MyString &rhs) const {
    return lhs.get_data() + rhs.get_data();
  }
};
}

void f() {
  std::string s1("My String");
  MyString s2(" + Your String");
  std::plus<MyString> p;

  std::cout << p(s1, s2).get_data() << std::endl;
}
Risk Assessment

Altering the standard namespace can cause undefined behavior in the C++ standard library.

Rule Severity Likelihood Remediation Cost Priority Level
DCL58-CPP High Unlikely Medium P6 L2
Related Guidelines
SEI CERT C++ Coding Standard DCL51-CPP. Do not declare or define a reserved identifier
Bibliography
[ INCITS 2014] Issue 2139, "What Is a User-Defined Type?"
[ ISO/IEC 14882-2014] Subclause 17.6.4.2.1, "Namespace std"
Subclause 17.6.4.2.2, "Namespace posix
Excerpt from SEI CERT C++ Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-cpp-coding-standard/rules/declarations-and-initialization-dcl/dcl58-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

std_extension

Invalid addition to std namespace

None

False

std_specialization

Invalid std template specialization

None

False

Options

std_specialization_blacklist

std_specialization_blacklist

Type: set[bauhaus.analysis.config.QualifiedName]

Default: {'std::add_const', 'std::add_cv', 'std::add_lvalue_reference', 'std::add_pointer', 'std::add_rvalue_reference', 'std::add_volatile', 'std::aligned_storage', 'std::aligned_union', 'std::alignment_of', 'std::binary_function', 'std::common_type', 'std::conditional', 'std::conjunction', 'std::decay', 'std::disjunction', 'std::enable_if', 'std::endian', 'std::extent', 'std::has_unique_object_representations', 'std::has_virtual_destructor', 'std::integral_constant', 'std::invoke_result', 'std::is_abstract', 'std::is_aggregate', 'std::is_arithmetic', 'std::is_array', 'std::is_assignable', 'std::is_base_of', 'std::is_class', 'std::is_compound', 'std::is_const', 'std::is_constructible', 'std::is_convertible', 'std::is_copy_assignable', 'std::is_copy_constructible', 'std::is_default_constructible', 'std::is_destructible', 'std::is_empty', 'std::is_enum', 'std::is_final', 'std::is_floating_point', 'std::is_function', 'std::is_fundamental', 'std::is_integral', 'std::is_invocable', 'std::is_invocable_r', 'std::is_literal_type', 'std::is_lvalue_reference', 'std::is_member_function_pointer', 'std::is_member_object_pointer', 'std::is_member_pointer', 'std::is_move_assignable', 'std::is_move_constructible', 'std::is_nothrow_assignable', 'std::is_nothrow_constructible', 'std::is_nothrow_convertible', 'std::is_nothrow_copy_assignable', 'std::is_nothrow_copy_constructible', 'std::is_nothrow_default_constructible', 'std::is_nothrow_destructible', 'std::is_nothrow_invocable', 'std::is_nothrow_invocable_r', 'std::is_nothrow_move_assignable', 'std::is_nothrow_move_constructible', 'std::is_nothrow_swappable', 'std::is_nothrow_swappable_with', 'std::is_null_pointer', 'std::is_object', 'std::is_pod', 'std::is_pointer', 'std::is_polymorphic', 'std::is_reference', 'std::is_rvalue_reference', 'std::is_same', 'std::is_scalar', 'std::is_signed', 'std::is_standard_layout', 'std::is_swappable', 'std::is_swappable_with', 'std::is_trivial', 'std::is_trivially_assignable', 'std::is_trivially_constructible', 'std::is_trivially_copy_assignable', 'std::is_trivially_copy_constructible', 'std::is_trivially_copyable', 'std::is_trivially_default_constructible', 'std::is_trivially_destructible', 'std::is_trivially_move_assignable', 'std::is_trivially_move_constructible', 'std::is_union', 'std::is_unsigned', 'std::is_void', 'std::is_volatile', 'std::make_signed', 'std::make_unsigned', 'std::negation', 'std::rank', 'std::remove_all_extents', 'std::remove_const', 'std::remove_cv', 'std::remove_cvref', 'std::remove_extent', 'std::remove_pointer', 'std::remove_reference', 'std::remove_volatile', 'std::result_of', 'std::unary_function', 'std::underlying_type', 'std::void_t'}

Templates in namespace std that must not be specialized.
 

std_specialization_whitelist

std_specialization_whitelist : set[bauhaus.analysis.config.QualifiedName] = {'std::common_type'}

Templates in namespace std that can be specialized (even when found on the blacklist).