mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
This PR separates the core cpp packs into `codeql/cpp-queries` and `codeql/cpp-all`. There are very few lines of code changed. Almost all changes are moving files around.
175 lines
6.5 KiB
Plaintext
175 lines
6.5 KiB
Plaintext
/**
|
|
* Provides utility predicates used by the pointless comparison queries.
|
|
*/
|
|
|
|
import cpp
|
|
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
|
|
|
/** Gets the lower bound of the fully converted expression. */
|
|
private float lowerBoundFC(Expr expr) { result = lowerBound(expr.getFullyConverted()) }
|
|
|
|
/** Gets the upper bound of the fully converted expression. */
|
|
private float upperBoundFC(Expr expr) { result = upperBound(expr.getFullyConverted()) }
|
|
|
|
/**
|
|
* Describes which side of a pointless comparison is known to be smaller.
|
|
*/
|
|
newtype SmallSide =
|
|
/**
|
|
* Represents that the left side of a pointless comparison is known to be smaller.
|
|
*/
|
|
LeftIsSmaller() or
|
|
/**
|
|
* Represents that the right side of a pointless comparison is known to be smaller.
|
|
*/
|
|
RightIsSmaller()
|
|
|
|
/**
|
|
* Holds if `cmp` is a comparison operation in which the left hand
|
|
* argument (which is at most `left`) is always strictly less than the
|
|
* right hand argument (which is at least `right`), and `ss` is
|
|
* `LeftIsSmaller`.
|
|
*
|
|
* Note that the comparison operation could be any binary comparison
|
|
* operator, for example,`==`, `>`, or `<=`.
|
|
*/
|
|
private predicate alwaysLT(ComparisonOperation cmp, float left, float right, SmallSide ss) {
|
|
ss = LeftIsSmaller() and
|
|
left = upperBoundFC(cmp.getLeftOperand()) and
|
|
right = lowerBoundFC(cmp.getRightOperand()) and
|
|
left < right
|
|
}
|
|
|
|
/**
|
|
* Holds if `cmp` is a comparison operation in which the left hand
|
|
* argument (which is at most `left`) is always less than or equal to
|
|
* the right hand argument (which is at least `right`), and `ss` is
|
|
* `LeftIsSmaller`.
|
|
*
|
|
* Note that the comparison operation could be any binary comparison
|
|
* operator, for example,`==`, `>`, or `<=`.
|
|
*/
|
|
private predicate alwaysLE(ComparisonOperation cmp, float left, float right, SmallSide ss) {
|
|
ss = LeftIsSmaller() and
|
|
left = upperBoundFC(cmp.getLeftOperand()) and
|
|
right = lowerBoundFC(cmp.getRightOperand()) and
|
|
left <= right and
|
|
// Range analysis is not able to precisely represent large 64 bit numbers,
|
|
// because it stores the range as a `float`, which only has a 53 bit mantissa.
|
|
// For example, the number `2^64-1` is rounded to `2^64`. This means that we
|
|
// cannot trust the result if the numbers are large. Note: there is only
|
|
// a risk of a rounding error causing an incorrect result if `left == right`.
|
|
// If `left` is strictly less than `right` then there is enough of a gap
|
|
// that we don't need to worry about rounding errors.
|
|
left.ulp() <= 1
|
|
}
|
|
|
|
/**
|
|
* Holds if `cmp` is a comparison operation in which the left hand
|
|
* argument (which is at least `left`) is always strictly greater than
|
|
* the right hand argument (which is at most `right`), and `ss` is
|
|
* `RightIsSmaller`.
|
|
*
|
|
* Note that the comparison operation could be any binary comparison
|
|
* operator, for example,`==`, `>`, or `<=`.
|
|
*/
|
|
private predicate alwaysGT(ComparisonOperation cmp, float left, float right, SmallSide ss) {
|
|
ss = RightIsSmaller() and
|
|
left = lowerBoundFC(cmp.getLeftOperand()) and
|
|
right = upperBoundFC(cmp.getRightOperand()) and
|
|
left > right
|
|
}
|
|
|
|
/**
|
|
* Holds if `cmp` is a comparison operation in which the left hand
|
|
* argument (which is at least `left`) is always greater than or equal
|
|
* to the right hand argument (which is at most `right`), and `ss` is
|
|
* `RightIsSmaller`.
|
|
*
|
|
* Note that the comparison operation could be any binary comparison
|
|
* operator, for example,`==`, `>`, or `<=`.
|
|
*/
|
|
private predicate alwaysGE(ComparisonOperation cmp, float left, float right, SmallSide ss) {
|
|
ss = RightIsSmaller() and
|
|
left = lowerBoundFC(cmp.getLeftOperand()) and
|
|
right = upperBoundFC(cmp.getRightOperand()) and
|
|
left >= right and
|
|
// Range analysis is not able to precisely represent large 64 bit numbers,
|
|
// because it stores the range as a `float`, which only has a 53 bit mantissa.
|
|
// For example, the number 2^64-1 is rounded to 2^64. This means that we
|
|
// cannot trust the result if the numbers are large. Note: there is only
|
|
// a risk of a rounding error causing an incorrect result if `left == right`.
|
|
// If `left` is strictly less than `right` then there is enough of a gap
|
|
// that we don't need to worry about rounding errors.
|
|
left.ulp() <= 1
|
|
}
|
|
|
|
/**
|
|
* Holds if `cmp` is a comparison operation that always has the
|
|
* result `value`, and either
|
|
* * `ss` is `LeftIsSmaller`, and the left hand argument is always at
|
|
* most `left`, the right hand argument at least `right`, and `left`
|
|
* is less than or equal to `right`; or
|
|
* * `ss` is `RightIsSmaller`, and the left hand argument is always at
|
|
* least `left`, the right hand argument at most `right`, and `left`
|
|
* is greater than or equal to `right`.
|
|
*
|
|
* For example, if the comparison `x < y` is always true because
|
|
* `x <= 3` and `5 <= y` then
|
|
* `pointlessComparison(x < y, 3, 5, true, LeftIsSmaller)` holds.
|
|
*
|
|
* Similarly, if the comparison `x < y` is always false because `x >= 9`
|
|
* and `7 >= y` then
|
|
* `pointlessComparison(x < y, 9, 7, false, RightIsSmaller)` holds.
|
|
*/
|
|
predicate pointlessComparison(
|
|
ComparisonOperation cmp, float left, float right, boolean value, SmallSide ss
|
|
) {
|
|
alwaysLT(cmp.(LTExpr), left, right, ss) and value = true
|
|
or
|
|
alwaysLE(cmp.(LEExpr), left, right, ss) and value = true
|
|
or
|
|
alwaysGT(cmp.(GTExpr), left, right, ss) and value = true
|
|
or
|
|
alwaysGE(cmp.(GEExpr), left, right, ss) and value = true
|
|
or
|
|
alwaysLT(cmp.(NEExpr), left, right, ss) and value = true
|
|
or
|
|
alwaysGT(cmp.(NEExpr), left, right, ss) and value = true
|
|
or
|
|
alwaysGE(cmp.(LTExpr), left, right, ss) and value = false
|
|
or
|
|
alwaysGT(cmp.(LEExpr), left, right, ss) and value = false
|
|
or
|
|
alwaysLE(cmp.(GTExpr), left, right, ss) and value = false
|
|
or
|
|
alwaysLT(cmp.(GEExpr), left, right, ss) and value = false
|
|
or
|
|
alwaysLT(cmp.(EQExpr), left, right, ss) and value = false
|
|
or
|
|
alwaysGT(cmp.(EQExpr), left, right, ss) and value = false
|
|
}
|
|
|
|
/**
|
|
* Holds if `cmp` is a pointless comparison (see `pointlessComparison`
|
|
* above) and `cmp` occurs in reachable code. The reason for excluding
|
|
* expressions that occur in unreachable code is that range analysis
|
|
* sometimes can deduce impossible ranges for them. For example:
|
|
*
|
|
* if (10 < x) {
|
|
* if (x < 5) {
|
|
* // Unreachable code
|
|
* return x; // x has an empty range: 10 < x && x < 5
|
|
* }
|
|
* }
|
|
*/
|
|
predicate reachablePointlessComparison(
|
|
ComparisonOperation cmp, float left, float right, boolean value, SmallSide ss
|
|
) {
|
|
pointlessComparison(cmp, left, right, value, ss) and
|
|
// Reachable according to control flow analysis.
|
|
reachable(cmp) and
|
|
// Reachable according to range analysis.
|
|
not exprWithEmptyRange(cmp.getAChild+())
|
|
}
|