The C++ Standard, [basic.types], paragraph 9 [ISO/IEC 14882-2014], states the following:
The object representation of an object of type
T
is the sequence of Nunsigned char
objects taken up by the object of typeT
, where N equalssizeof(T)
. The value representation of an object is the set of bits that hold the value of typeT
.
Some The narrow character types , such as integral types like int
and wchar_t
, have an object representation comprised (char
, signed char
, and unsigned char
)—as well as some other integral types on specific platforms—have an object representation that consists solely of the bits from the object's value representation. For such types, accessing any of the bits of the value representation is well-defined behavior. This form of object representation allows a programmer to use byte-wise access of the objectaccess and modify an object solely based on its bit representation, such as by calling std::memcmp()
on it's its object representation.
Other types, such as classes, may not have an object representation comprised composed solely of the bits from the object's value representation. For instance, classes may have bitfield bit-field data members, padding inserted between data members, a vtable to support virtual method dispatch, or have data members declared with different access privileges. For such types, accessing bits of the object representation that are not part of the object's value representation may result in undefined behavior depending on how those bits are accessed.
...
In this noncompliant code example, the complete object representation is accessed when comparing two objects of type S
. Per the C++ Standard, [class], paragraph 13 [ISO/IEC 14882-2014], classes may be padded with data to ensure that they are properly aligned in memory. The contents of the padding and the amount of padding added is implementation-defined. This can lead to incorrect results when comparing the object representation of classes instead of the value representation, as the padding may assume different unspecified values for each object instance.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <cstring> struct S { unsigned char buff_typebuffType; int size; }; void f(const S &s1, const S &s2) { if (!std::memcmp(&s1, &s2, sizeof(S))) { // ... } } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
struct S { unsigned char buff_typebuffType; int size; friend bool operator==(const S &LHSlhs, const S &RHSrhs) { return LHSlhs.buff_typebuffType == RHSrhs.buff_typebuffType && LHSlhs.size == RHSrhs.size; } }; void f(const S &s1, const S &s2) { if (s1 == s2) { // ... } } |
Noncompliant Code Example
In this noncompliant code example, std::memset()
is used to clear the internal state of an object. An implementation may store a vtable within the object instance due to the presence of a virtual function, and that vtable is subsequently overwritten by the call to std::memset()
, leading to undefined behavior when virtual method dispatch is required.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <cstring>
struct S {
int i, j, k;
// ...
virtual void f();
};
void f() {
S *s = new S;
// ...
std::memset(s, 0, sizeof(S));
// ...
s->f(); // undefined behavior
} |
Compliant Solution
In this compliant solution, the data members of S
are cleared explicitly instead of calling std::memset().
Code Block | ||||
---|---|---|---|---|
| ||||
struct S {
int i, j, k;
// ...
virtual void f();
void clear() { i = j = k = 0; }
};
void f() {
S *s = new S;
// ...
s->clear();
// ...
s->f(); // ok
} |
Exceptions
EXP62-CPP-EX1: It is permissible to access the bits of an object representation when that access is otherwise unobservable in well-defined code. Specifically, reading bits that are not part of the value representation is permissible when there is no reliance or assumptions placed on their values, and writing bits that are not part of the value representation is only permissible when those bits are padding bits. This exception does not permit writing to bits that are part of the object representation aside from padding bits, such as overwriting a vtable pointer.
For instance, it is acceptable to call std::memcpy()
on an object containing a bit-field, as in the following example, because the read and write of the padding bits cannot be observed. However, the code must still comply with OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <cstring>
struct S {
int i : 10;
int j;
};
void f(const S &s1) {
S &s2;
std::memcpy(&s2, &s1, sizeof(S));
} |
Code that complies with this exception must still comply with OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions.
Risk Assessment
The effects of accessing bits of an object representation that are not part of the object's value representation can range from implementation-defined behavior (such as assuming the layout of fields with differing access controls) to code execution vulnerabilities (such as overwriting the vtable pointer).
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP62-CPP | High | Probable | High | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|
Astrée |
| invalid_pointer_dereference uninitialized_variable_use | |||||||
CodeSonar |
| BADFUNC.MEMCMP BADFUNC.MEMSET | Use of memcmp Use of memset | ||||||
Helix QAC |
| DF4726, DF4727, DF4728, DF4729, DF4731, DF4732, DF4733, DF4734 | |||||||
Klocwork |
| CERT.MEMCMP.PADDED_DATA CWARN.MEM.NONPOD | |||||||
LDRA tool suite |
| 618 S | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_CPP-EXP62-a | Do not compare objects of a class that may contain padding bits with C standard library functions | ||||||
Polyspace Bug Finder |
| CERT C++: EXP62-CPP | Checks for access attempts on padding and vtable bits (rule fully covered). | ||||||
PVS-Studio |
| V598, V780, V1084 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions |
Bibliography
...