Several C Standard Library standard library functions perform bytewise operations on objects. For instance instance, std::memcmp()
compares the bytes comprising the object representation of two objects, and std::memcpy()
copies the bytes comprising an object representation into a destination buffer. However, for some object types, this it results in undefined or abnormal program behavior.
...
A standard-layout class is a class that:
— has no non-static data members of type non-standard-layout class (or array of such types) or reference,
— has no virtual functions and no virtual base classes,
— has the same access control for all non-static data members,
— has no non-standard-layout base classes,
— either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
— has no base classes of the same type as the first non-static data member.
Do not use std::memset()
to initialize an object of nontrivial class type as it may not properly initialize the value representation of the object. Do not use std::memcpy()
(or related bytewise copy functions) to initialize a copy of an object of nontrivial class type, as it may not properly initialize the value representation of the copy. Do not use std::memcmp()
(or related bytewise comparison functions) to compare objects of nonstandard-layout class type, as it may not properly compare the value representations of the objects. In all cases, it is best to prefer the alternatives:
C Standard Library Function | C++ Equivalent Functionality |
---|---|
std::memset() | Class constructor |
std::memcpy() ,
std::memmove() ,
std::strcpy() | Class copy constructor or operator=() |
std::memcmp() ,
std::strcmp() | operator<() , operator>() , operator==() , or operator!=() |
...
In this noncompliant code example, a nontrivial class object is initialized by calling its default constructor , but is later reinitialized to its default state using std::memset()
. This , which does not properly reinitialize the object, leading . Improper reinitialization leads to class invariants not holding in later uses of the object.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <cstring> #include <iostream> class C { int ScalingFactor; int OtherData; public: C() : ScalingFactor(1) {} void SetOtherData(int I); int f(int i) { return i / ScalingFactor; } // ... }; void f() { C c; // ... codeCode that mutates c ... // Reinitialize c to its default state std::memset(&c, 0, sizeof(C)); std::cout << c.f(100) << std::endl; } |
...
In this compliant solution, the call to std::memset()
is replaced with a default-initialized copy-and-swap operation called clear()
. This operation ensures that the object is initialized to its default state properly, and it behaves properly for object types that have optimized assignment operators that fail to clear all data members of the object being assigned into.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> #include <utility> class C { int ScalingFactor; int OtherData; public: C() : ScalingFactor(1) {} void SetOtherData(int I); int f(int i) { return i / ScalingFactor; } // ... }; template <typename T> T& clear(T &o) { using std::swap; T empty; swap(o, empty); return o; } void f() { C c; // ... codeCode that mutates c ... // Reinitialize c to its default state clear(c); std::cout << c.f(100) << std::endl; } |
...
In this noncompliant code example, std::memcpy()
is used to create a copy of an object of nontrivial type C
. However, because each object instance attempts to delete the int *
in C::~C()
, this can lead to double-free vulnerabilities may occur because the same pointer value will be copied into c2
.
...
In this noncompliant code example, std::memcmp()
is used to compared two objects of nonstandard-layout type. Because std::memcmp()
performs a bytewise comparison of the object representations, if the implementation uses a vtable pointer as part of the object representation, this it will compare vtable pointers. If the dynamic type of either c1
or c2
is a derived class of type C
, the comparison may fail despite the value representation of either object.
...
In this compliant solution, C
defines an equality operator that is used instead of calling std::memcmp()
. This solution ensures that only the value representation of the objects is considered when performing the comparison.
...
Most violations of this rule will result in abnormal program behavior. However, overwriting implementation details of the object representation can lead to code execution vulnerabilities.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
OOP57-CPP | High | Probable | High | P6 | L2 |
...
[ISO/IEC 14882-2014] | Subclause 3.9, "Types" Subclause 3.10, "Lvalues and Rvalues" Clause 9, "Classes" |
...