Main Content

AUTOSAR C++14 Rule A12-0-2

Bitwise operations and operations that assume data representation in memory shall not be performed on objects

Since R2020b

Description

Rule Definition

Bitwise operations and operations that assume data representation in memory shall not be performed on objects.

Rationale

In C++, object representation in memory might include:

  • Data members declared with different access privileges

  • Bit-field data members

  • Padding bytes between data members

  • Padding bytes at the end of data members

  • Pointers to the vtable to support virtual functions

The arrangement of these different parts of an object in memory is environment dependent. In addition, static data members or function members of an object are stored in a separate physical location in memory. When you perform bitwise operation on an object by assuming certain arrangement of data in memory, you might inadvertently assume incorrectly, and access bits are not part of the value representation of the object. Accessing these bits can lead to undefined behavior.

Consider this class that contains a virtual function:

class notPOD{
public:
	virtual void foo();
	int value;
protected:
	double dvalue;

};
//... 
int main(){
	notPOD Obj;
	std::memset(&Obj, 57, 2); // attempts to set Obj::value to 57
}
When Obj is stored in a memory block, the block contains a pointer to the virtual table in addition to the variables Obj::value and Obj::dvalue. The size of this pointer or its location in memory can depend on the environment. In main(), std::memset() attempts to set the value of Obj::value by assuming that:

  • Obj::value is the first block in the memory representation of Obj.

  • Obj::value is represented by 2 bytes in the memory.

Because these assumptions are generally not correct, using std::memset() can lead to undefined behavior. For instance, if you inadvertently modify the pointer to virtual table, calling foo() can invoke an unexpected function.

The representation of class and structures in memory is environment-dependent and can contain additional bytes alongside the value representation. Relying on the data representation of an object to perform bitwise operations can result in modifying bits that are not part of the value representation, leading to undefined behavior. Avoid operations that assume a certain representation of an object in memory to access its bits. To perform operations on a class, use dedicated member functions, overloaded operators, or mutators.

Polyspace Implementation

The C functions that access accesses memory bits includes std::memset(), std::memcpy(), std::memmove(), std::strcpy(), std::memcmp(), std::strcmp(). Polyspace® flags a statement when:

  • You use the C functions to initialize or copy initialize nontrivial objects

  • You use the C functions to compare nonstandard layout objects

  • You use the C functions on any objects that contain padding data

The statements containing the noncompliant operations are flagged and relevant class declarations are highlighted. For definitions of trivial and standard layout classes, see the C++ Standard, [class], paragraphs 6 and 7 respectively.

As an exception, Polyspace does not flag operations that use the C functions to access the memory bits of trivial and standard layout objects with no padding data. Although using bitwise operation on trivial and standard layout classes with no padding data complies with this rule, it is not a good practice. Instead, use dedicated member function, overloaded operators, or mutators.

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

Consider this code that contains these classes:

  • TrivialClass is a trivial class with padding data and an overloaded operator|=.

  • NonTrivialClass is a nontrivial class with a virtual function and an overloaded operator==.

These classes are represented in different ways in the memory. This example shows how Polyspace flags bitwise operations that are performed on such objects.

#include <cstdint>
#include <cstring>
class TrivialClass
{
public:
	TrivialClass() = default;
	TrivialClass(uint8_t c, uint32_t i, int8_t d) :
	c(c), i(i), d(d) {}
	TrivialClass& operator |=(const TrivialClass& other)
	{
		uint32_t buf[4] {this->c|other.c,this->i|other.i,this->d|other.d};
		memcpy(this, buf, sizeof(uint32_t) * 3); //Noncompliant
		return *this;
	}
	
private:
	uint8_t c;
	uint32_t i;
	int8_t d;
};

class NonTrivialClass 
{
public:
	NonTrivialClass() = default;
	NonTrivialClass(uint32_t a, uint32_t b, uint32_t c) : 
	a(a), b(b), c(c){}
	bool operator==(const NonTrivialClass& rhs) const noexcept
	{
		return a==rhs.a && b==rhs.b && c==rhs.c;
	}
	virtual ~NonTrivialClass() {} 
private:
	uint32_t a;
	uint32_t b;
	uint32_t c;
};

int main(void)
{
	TrivialClass A, A1{3,5,7};
	NonTrivialClass B, B1{10,11,12};
	std::memset(&A, 3, 1); //Noncompliant
	A |= A1; 
	if (!std::memcmp(&A, &A1, sizeof(TrivialClass))) {} //Noncompliant
	std::memcpy(&B, &B1, sizeof(NonTrivialClass)); //Noncompliant
	if (B == B1){} //Compliant
	return 0;
}

  • Polyspace flags the statement std::memset(&A, 3, 1); because in this statement, std::memset() modifies the individual bits in the memory representation of the trivial object A including padding data. Accessing padding data bits of an object is a violation of this rule even if the object is a trivial class object. For the same reason, Polyspace flags the statement in the definition of TrivialClass::operator|= containing memcopy().

  • Polyspace flags the statement std::memcpy(&B, &B1, sizeof(NonTrivialClass)); because std::memcpy() accesses the individual bits in the memory representation of the nontrivial object B including the pointer to vtable. This pointer is not part of the value representation and accessing this pointer is a violation of this rule.

  • Polyspace does not flag the statement if(B==B1) because NonTrivialClass has an overloaded operator== that can compare B and B1 without accessing their individual bits.

Check Information

Group: Special member functions
Category: Required, Partially automated

Version History

Introduced in R2020b