...
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 class
, struct
, union
, 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:
Code Block | ||||
---|---|---|---|---|
| ||||
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.
Code Block | ||||
---|---|---|---|---|
| ||||
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.
Code Block | ||||
---|---|---|---|---|
| ||||
#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
.
Code Block | ||||
---|---|---|---|---|
| ||||
#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, and 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.
Code Block | ||||
---|---|---|---|---|
| ||||
#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 |
---|---|---|---|---|---|
DCL61DCL58-CPP | High | Unlikely | Medium | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
| -q & Name Check | ||||||||
SonarQube C/C++ Plugin |
| S3470 |
Related Vulnerabilities
Search for other vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
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 " |
...