rspec/rules/S6214/cfamily/rule.adoc
Fred Tingaud d3cfe19d7e
Fix broken or dangerous backquotes
Co-authored-by: Marco Borgeaud <89914223+marco-antognini-sonarsource@users.noreply.github.com>
2023-10-30 10:33:56 +01:00

95 lines
2.7 KiB
Plaintext

Compare integers of mixed signedness safely using ``++std::cmp_*++`` functions to avoid any unexpected results.
== Why is this an issue?
Comparison between `signed` and `unsigned` integers is dangerous because it produces counter-intuitive results due to implicit conversions.
When a signed integer is compared to an unsigned one, the former might be converted to unsigned.
Since {cpp}20, the conversion preserves the two's-complement bit pattern of the signed value that always corresponds to a large unsigned result.
For example, `2U < -1` is `true`.
This rule raises an issue when an unsigned integer is compared with a negative value.
=== What is the potential impact
Integer comparisons are often used in branch and loop conditions.
An unexpected result from one of these conditions can lead to hard-to-detect issues, such as unexpected infinite loops.
For example, using container size functions in a comparison can lead to such a problem since these return an unsigned integer value.
== How to fix it
{cpp}20 introduced a remedy to this common pitfall: a family of ``++std::cmp_*++`` functions defined in the `<utility>` header.
These functions correctly handle negative numbers and lossy integer conversion.
For example, `std::cmp_less(2U, -1)` is `false`.
=== Code examples
==== Noncompliant code example
[source,cpp,diff-id=1,diff-type=noncompliant]
----
bool less = 2U < -1; // Noncompliant
unsigned x = 1;
signed y = -1;
if (x < y) { // Noncompliant
// ...
}
bool fun(int x, std::vector<int> const& v) {
return x < v.size(); // Noncompliant: if x is negative, it is converted to unsigned, losing its value.
}
std::vector<int> v = foo();
if (-1 < v.size() && v.size() < 100) { // Noncompliant: -1 < v.size() is false for all sizes.
// -1 converted to unsigned is larger than any int value
}
----
==== Compliant solution
[source,cpp,diff-id=1,diff-type=compliant]
----
bool less = std::cmp_less(2U, -1); // Compliant
unsigned x = 1;
signed y = -1;
if (std::cmp_less(x, y)) { // Compliant
// ...
}
bool fun(int x, std::vector<int> const& v) {
return std::cmp_less(x, v.size()); // Compliant
}
std::vector<int> v = foo();
if (0 <= v.size() && v.size() < 100) { // Compliant, even though v.size() returns an unsigned integer
}
----
== Resources
=== Documentation
* {cpp} reference - https://en.cppreference.com/w/cpp/utility/intcmp[std::cmp_* functions]
=== Related rules
* S845 - a more generic rule about mixing signed and unsigned values.
* S6183 - a version of this rule that triggers when any signed and unsigned variables are compared.
ifdef::env-github,rspecator-view[]
'''
== Comments And Links
(visible only on this page)
=== relates to: S845
=== relates to: S6183
endif::env-github,rspecator-view[]