IssueBytewise operations on
nontrivial class object occurs when you use C Standard library functions to
perform bytewise operation on non-trivial or non-standard layout class type objects. For
definitions of trivial and standard layout classes, see the C++ Standard, [class], paragraphs 6
and 7 respectively.
The checker raises a defect you initialize or
copy non-trivial class type objects using these functions:
std::memset
std::memcpy
std::strcpy
std::memmove
Or when you compare non-standard layout class type objects using these functions:
Bytewise operations on nontrivial class
object raises no defect if the bytewise operation is performed through an
alias. For example no defect is raised in the bytewise comparison and copy operations in
this code. The bytewise operations use dptr and
sptr, the aliases of non-trivial or non-standard layout class objects
d and s.
void func(NonTrivialNonStdLayout *d, const NonTrivialNonStdLayout *s)
{
void* dptr = (void*)d;
const void* sptr = (void*)s;
// ...
// ...
// ...
if (!std::memcmp(dptr, sptr, sizeof(NonTrivialNonStdLayout))) {
(void)std::memcpy(dptr, sptr, sizeof(NonTrivialNonStdLayout));
// ...
}
}
|
RiskPerforming bytewise comparison operations by
using C Standard library functions on non-trivial or non-standard layout class type object
might result in unexpected values due to implementation details. The object representation
depends on the implementation details, such as the order of private and public members, or
the use of virtual function pointer tables to represent the object.
Performing bytewise setting operations by using
C Standard library functions on non-trivial or non-standard layout class type object can
change the implementation details. The operation might result in abnormal program behavior
or a code execution vulnerability. For instance, if the address of a member function is
overwritten, the call to this function invokes an unexpected function.
FixTo perform bytewise operations non-trivial or
non-standard layout class type object, use these C++ special member functions instead of C
Standard library functions.
| C Standard Library Functions | C++ Member Functions |
|---|
std::memset
| Class constructor |
std::memcpy
std::strcpy
std::memmove
| Class copy constructor Class move
constructor Copy assignment operator Move assignment
operator |
std::memcmp
std::strcmp
| operator<()
operator>()
operator==()
operator!=()
|
Example - Using memset with
non-trivial class object#include <cstring>
#include <iostream>
#include <utility>
class nonTrivialClass
{
int scalingFactor;
int otherData;
public:
nonTrivialClass() : scalingFactor(1) {}
void set_other_data(int i);
int f(int i)
{
return i / scalingFactor;
}
// ...
};
void func()
{
nonTrivialClass c;
// ... Code that mutates c ...
std::memset(&c, 0, sizeof(nonTrivialClass));
std::cout << c.f(100) << std::endl;
}In this example, func() uses
std::memset to reinitialize non-trivial class object
c after it is first initialized with its default constructor. This
bytewise operation might not properly initialize the value representation of
c.
Correction — Define Function Template That Uses
std::swapOne possible correction is to define a function
template clear() that uses std::swap to perform a
swap operation. The call to clear()properly reinitializes object
c by swapping the contents of c and default
initialized object empty.
#include <cstring>
#include <iostream>
#include <utility>
class nonTrivialClass
{
int scalingFactor;
int otherData;
public:
nonTrivialClass() : scalingFactor(1) {}
void set_other_data(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 func()
{
nonTrivialClass c;
// ... Code that mutates c ...
clear(c);
std::cout << c.f(100) << std::endl;
}