...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <cstddef>
#include <iostream>
template <typename Ty>
bool in_range(const Ty *test, const Ty *r, size_t n) {
return 0 < (test - r) && (test - r) < (std::ptrdiff_t)n;
}
void f() {
double foo[10];
double *x = &foo[0];
double bar;
std::cout << std::boolalpha << in_range(&bar, x, 10);
} |
...
In this noncompliant code example, the in_range() function is implemented using a comparison expression instead of subtraction. The C++ Standard, [expr.rel], paragraph 4 [ISO/IEC 14882-2014], states the following:
If two operands
pandqcompare equal,p<=qandp>=qboth yieldtrueandp<qandp>qboth yieldfalse. Otherwise, if a pointerpcompares greater than a pointerq,p>=q,p>q,q<=p, andq<pall yieldtrueandp<=q,p<q,q>=p, andq>pall yieldfalse. Otherwise, the result of each of the operators is unspecified.
| Page properties | ||
|---|---|---|
| ||
The "Thus" statement below is incomplete. What is required to make such a statement is p3, which is a total mess because it doesn't say WHAT should happen when two pointers not of the same container are compared. The assumption is that this is what causes us to fall into the final "otherwise" clause of p4, but I think a core issue may be in order. Once that is resolved, we can update this section accordingly. |
...
This noncompliant code example is roughly equivalent to the previous example, except that it uses iterators in place of raw pointers. As with the previous example, the in_range_impl() function exhibits unspecified behavior when the iterators do not refer into the same container because the operational semantics of a < b on a random access iterator are b - a > 0, and >= is implemented in terms of <.
...
In this noncompliant code example, std::less<> is used in place of the < operator. The C++ Standard, [comparisons], paragraph 14 [ISO/IEC 14882-2014], states the following:
For templates
greater,less,greater_equal, andless_equal, the specializations for any pointer type yield a total order, even if the built-in operators<,>,<=,>=do not.
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <functional>
#include <iostream>
template <typename Ty>
bool in_range(const Ty *test, const Ty *r, size_t n) {
std::less<const Ty *> less;
return !less(test, r) && less(test, r + n);
}
void f() {
double foo[10];
double *x = &foo[0];
double bar;
std::cout << std::boolalpha << in_range(&bar, x, 10);
} |
Compliant Solution
In this This compliant solution , demonstrates a fully portable, but likely inefficient equality comparing , implementation of in_range() that compares test against each possible address in the range [r, n] is used to implement the in_range() function:. A compliant solution that is both efficient and fully portable is currently unknown.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <iostream>
template <typename Ty>
bool in_range(const Ty *test, const Ty *r, size_t n) {
auto *cur = reinterpret_cast<const unsigned char *>(r);
auto *end = reinterpret_cast<const unsigned char *>(r + n);
auto *testPtr = reinterpret_cast<const unsigned char *>(test);
for (; cur != end; ++cur) {
if (cur == testPtr) {
return true;
}
}
return false;
}
void f() {
double foo[10];
double *x = &foo[0];
double bar;
std::cout << std::boolalpha << in_range(&bar, x, 10);
}
|
Risk Assessment
Rule | Severity | Likelihood |
|---|
Detectable | Repairable | Priority | Level |
|---|---|---|---|
CTR54-CPP | Medium | Probable |
No | No |
P4 |
L3 |
Automated Detection
Tool | Version | Checker | Description |
|---|
2761, 2762, 2763,
2766, 2767, 2768,
2771, 2772, 2773
| Astrée |
| invalid_pointer_subtraction invalid_pointer_comparison | |||||||
| CodeSonar |
| LANG.STRUCT.CUP | Comparison of Unrelated Pointers | ||||||
| Helix QAC |
| DF2668, DF2761, DF2762, DF2763, DF2766, DF2767, DF2768 | |||||||
| LDRA tool suite |
| 70 S, 87 S, 437 S, 438 S | Enhanced Enforcement | ||||||
| Parasoft C/C++test |
| CERT_CPP-CTR54-a | Do not compare iterators from different containers | ||||||
| Polyspace Bug Finder |
| CERT C++: CTR54-CPP | Checks for subtraction or comparison between iterators from different containers (rule partially covered). |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
| SEI CERT C Coding Standard | ARR36-C. Do not subtract or compare two pointers that do not refer to the same array |
| MITRE CWE | CWE-469, Use of Pointer Subtraction to Determine Size |
Bibliography
| [Banahan |
| 2003] | Section 5.3, "Pointers" Section 5.7, "Expressions Involving Pointers" |
| [ISO/IEC 14882-2014] | Subclause 5.7, "Additive Operators" |
...
...