rspec/rules/S5000/cfamily/rule.adoc
2023-09-19 08:14:39 +02:00

120 lines
3.0 KiB
Plaintext

The function ``++memcmp++`` only returns meaningful results for objects of trivially copyable types without padding. This includes scalar types, arrays, and trivially copyable classes.
== Why is this an issue?
`memcmp` compares the raw memory representation of two objects (what the standard calls their _object representation_). When objects are not trivially copyable or contain padding, they could have different raw memory representations even though they store identical values. So the result of `memcmp` is not meaningful.
Padding refers to the insertion of additional bits into a structure or class to ensure proper alignment of its members in memory.
include::../../../shared_content/cfamily/trivially_copyable_types.adoc[]
== How to fix it
The comparison operator `operator==` should be defined and used instead of `memcmp` when the types are not trivially copyable or contain padding.
This allows comparing member by member to check object equality.
=== Code examples
==== Noncompliant code example
[source,c,diff-id=1,diff-type=noncompliant]
----
struct Shape { // Trivially copyable, but will contain padding after the bool on most architectures
bool visible;
int x;
int y;
};
bool isSame(Shape *s1, Shape *s2)
{
return memcmp(s1, s2, sizeof(Shape)) == 0; // Noncompliant
}
----
==== Compliant solution
[source,c,diff-id=1,diff-type=compliant]
----
struct Shape { // Trivially copyable, but will contain padding after the bool on most architectures
bool visible;
int x;
int y;
};
bool isSame(Shape *s1, Shape *s2)
{
return s1->visible == s2->visible && s1->x == s2->x && s1->y == s2->y;
}
----
==== Noncompliant code example
[source,cpp,diff-id=2,diff-type=noncompliant]
----
class Resource { // Not trivially copyable
public:
Ptr* ptr;
~Resource();
};
bool isSame(Resource *r1, Resource *r2)
{
return memcmp(r1, r2, sizeof(Resource)) == 0; // Noncompliant
}
----
==== Compliant solution
[source,cpp,diff-id=2,diff-type=compliant]
----
class Resource { // Not trivially copyable
public:
Ptr* ptr;
~Resource();
};
bool operator==(Resource const &r1, Resource const &r2) {
return r1.ptr == r2.ptr;
}
bool isSame(Resource *r1, Resource *r2)
{
return (*r1) == (*r2);
}
----
== Resources
=== Documentation
* {cpp} reference - https://en.cppreference.com/w/cpp/language/classes#Trivially_copyable_class[Definition of a trivially copyable class].
=== Related rules
* S4999 - "memcpy", "memmove", and "memset" should only be called with pointers to trivially copyable types
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
Use "operator==" to check object equality, "XXX" is not a trivially copyable type without padding.
Compare member by member to check object equality, "XXX" contains padding.
'''
== Comments And Links
(visible only on this page)
=== on 6 Nov 2018, 20:43:32 Ann Campbell wrote:
Double-check me [~loic.joly]
=== on 7 Nov 2018, 08:57:39 Loïc Joly wrote:
Looks good to me.
endif::env-github,rspecator-view[]