diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll b/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll index 12361228202d..d68207f2d370 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisDefinition.qll @@ -50,7 +50,7 @@ abstract class SimpleRangeAnalysisDefinition extends RangeSsaDefinition { * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for * recursive calls to get the bounds of their dependencies. */ - abstract float getLowerBounds(StackVariable v); + abstract QlBuiltins::BigInt getLowerBounds(StackVariable v); /** * Gets the upper bound of the variable `v` defined by this definition. @@ -59,7 +59,7 @@ abstract class SimpleRangeAnalysisDefinition extends RangeSsaDefinition { * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for * recursive calls to get the bounds of their dependencies. */ - abstract float getUpperBounds(StackVariable v); + abstract QlBuiltins::BigInt getUpperBounds(StackVariable v); } import SimpleRangeAnalysisInternal diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll b/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll index c8c1110b3af8..018286417efb 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/models/interfaces/SimpleRangeAnalysisExpr.qll @@ -21,7 +21,7 @@ abstract class SimpleRangeAnalysisExpr extends Expr { * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for * recursive calls to get the bounds of their children. */ - abstract float getLowerBounds(); + abstract QlBuiltins::BigInt getLowerBounds(); /** * Gets the upper bound of the expression. @@ -30,7 +30,7 @@ abstract class SimpleRangeAnalysisExpr extends Expr { * `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for * recursive calls to get the bounds of their children. */ - abstract float getUpperBounds(); + abstract QlBuiltins::BigInt getUpperBounds(); /** * Holds if the range this expression depends on the definition `srcDef` for @@ -70,9 +70,9 @@ private class Empty extends SimpleRangeAnalysisExpr { this = this and none() } - override float getLowerBounds() { none() } + override QlBuiltins::BigInt getLowerBounds() { none() } - override float getUpperBounds() { none() } + override QlBuiltins::BigInt getUpperBounds() { none() } override predicate dependsOnChild(Expr child) { none() } } diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll index 20e3f6abb17f..2372062f4c2c 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantBitwiseAndExprRange.qll @@ -46,34 +46,37 @@ private class ConstantBitwiseAndExprRange extends SimpleRangeAnalysisExpr { result = this.(AssignAndExpr).getRValue() } - override float getLowerBounds() { + override QlBuiltins::BigInt getLowerBounds() { // If an operand can have negative values, the lower bound is unconstrained. // Otherwise, the lower bound is zero. - exists(float lLower, float rLower | + exists(QlBuiltins::BigInt lLower, QlBuiltins::BigInt rLower | lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and ( - (lLower < 0 or rLower < 0) and + (lLower < 0.toBigInt() or rLower < 0.toBigInt()) and result = exprMinVal(this) or // This technically results in two lowerBounds when an operand range is negative, but // that's fine since `exprMinVal(x) <= 0`. We can't use an if statement here without // non-monotonic recursion issues - result = 0 + result = 0.toBigInt() ) ) } - override float getUpperBounds() { + override QlBuiltins::BigInt getUpperBounds() { // If an operand can have negative values, the upper bound is unconstrained. // Otherwise, the upper bound is the minimum of the upper bounds of the operands - exists(float lLower, float lUpper, float rLower, float rUpper | + exists( + QlBuiltins::BigInt lLower, QlBuiltins::BigInt lUpper, QlBuiltins::BigInt rLower, + QlBuiltins::BigInt rUpper + | lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and rUpper = getFullyConvertedUpperBounds(this.getRightOperand()) and ( - (lLower < 0 or rLower < 0) and + (lLower < 0.toBigInt() or rLower < 0.toBigInt()) and result = exprMaxVal(this) or // This technically results in two upperBounds when an operand range is negative, but diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantShiftExprRange.qll b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantShiftExprRange.qll index 3f300d7aa8d6..7939f9edf89d 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantShiftExprRange.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/ConstantShiftExprRange.qll @@ -2,14 +2,14 @@ private import cpp private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils -float evaluateConstantExpr(Expr e) { - result = e.getValue().toFloat() +QlBuiltins::BigInt evaluateConstantExpr(Expr e) { + result = parseAsBigInt(e.getValue()) or // This handles when a constant value is put into a variable // and the variable is used later exists(SsaDefinition defn, StackVariable sv | defn.getAUse(sv) = e and - result = defn.getDefiningValue(sv).getValue().toFloat() + result = parseAsBigInt(defn.getDefiningValue(sv).getValue()) ) } @@ -18,16 +18,18 @@ float evaluateConstantExpr(Expr e) { // architecture where the shift value is masked with 0b00011111, but we can't // assume the architecture). bindingset[val] -private predicate isValidShiftExprShift(float val, Expr l) { - val >= 0 and +private predicate isValidShiftExprShift(QlBuiltins::BigInt val, Expr l) { + val >= 0.toBigInt() and // We use getFullyConverted because the spec says to use the *promoted* left operand - val < (l.getFullyConverted().getUnderlyingType().getSize() * 8) + val < (l.getFullyConverted().getUnderlyingType().getSize() * 8).toBigInt() } bindingset[val, shift, max_val] -private predicate canLShiftOverflow(int val, int shift, int max_val) { +private predicate canLShiftOverflow( + QlBuiltins::BigInt val, QlBuiltins::BigInt shift, QlBuiltins::BigInt max_val +) { // val << shift = val * 2^shift > max_val => val > max_val/2^shift = max_val >> b - val > max_val.bitShiftRight(shift) + val > max_val.bitShiftRightSigned(shift.toInt()) } /** @@ -65,7 +67,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr { exists(evaluateConstantExpr(l)) and not exists(evaluateConstantExpr(r)) or // If the right operand is a constant, check if it is a valid shift expression - exists(float constROp | + exists(QlBuiltins::BigInt constROp | constROp = evaluateConstantExpr(r) and isValidShiftExprShift(constROp, l) ) ) @@ -82,8 +84,11 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr { result = this.(AssignRShiftExpr).getRValue() } - override float getLowerBounds() { - exists(int lLower, int lUpper, int rLower, int rUpper | + override QlBuiltins::BigInt getLowerBounds() { + exists( + QlBuiltins::BigInt lLower, QlBuiltins::BigInt lUpper, QlBuiltins::BigInt rLower, + QlBuiltins::BigInt rUpper + | lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and @@ -92,7 +97,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr { rLower <= rUpper | if - lLower < 0 + lLower < 0.toBigInt() or not ( isValidShiftExprShift(rLower, this.getLeftOperand()) and @@ -105,12 +110,15 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr { result = exprMinVal(this) else // We can get the smallest value by shifting the smallest bound by the largest bound - result = lLower.bitShiftRight(rUpper) + result = lLower.bitShiftRightSigned(rUpper.toInt()) ) } - override float getUpperBounds() { - exists(int lLower, int lUpper, int rLower, int rUpper | + override QlBuiltins::BigInt getUpperBounds() { + exists( + QlBuiltins::BigInt lLower, QlBuiltins::BigInt lUpper, QlBuiltins::BigInt rLower, + QlBuiltins::BigInt rUpper + | lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and @@ -119,7 +127,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr { rLower <= rUpper | if - lLower < 0 + lLower < 0.toBigInt() or not ( isValidShiftExprShift(rLower, this.getLeftOperand()) and @@ -132,7 +140,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr { result = exprMaxVal(this) else // We can get the largest value by shifting the largest bound by the smallest bound - result = lUpper.bitShiftRight(rLower) + result = lUpper.bitShiftRightSigned(rLower.toInt()) ) } @@ -178,7 +186,7 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr { exists(evaluateConstantExpr(l)) and not exists(evaluateConstantExpr(r)) or // If the right operand is a constant, check if it is a valid shift expression - exists(float constROp | + exists(QlBuiltins::BigInt constROp | constROp = evaluateConstantExpr(r) and isValidShiftExprShift(constROp, l) ) ) @@ -195,8 +203,11 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr { result = this.(AssignLShiftExpr).getRValue() } - override float getLowerBounds() { - exists(int lLower, int lUpper, int rLower, int rUpper | + override QlBuiltins::BigInt getLowerBounds() { + exists( + QlBuiltins::BigInt lLower, QlBuiltins::BigInt lUpper, QlBuiltins::BigInt rLower, + QlBuiltins::BigInt rUpper + | lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and @@ -205,7 +216,7 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr { rLower <= rUpper | if - lLower < 0 + lLower < 0.toBigInt() or not ( isValidShiftExprShift(rLower, this.getLeftOperand()) and @@ -222,12 +233,15 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr { // If necessary, we may be able to improve this bound in the future if canLShiftOverflow(lUpper, rUpper, exprMaxVal(this)) then result = exprMinVal(this) - else result = lLower.bitShiftLeft(rLower) + else result = lLower.bitShiftLeft(rLower.toInt()) ) } - override float getUpperBounds() { - exists(int lLower, int lUpper, int rLower, int rUpper | + override QlBuiltins::BigInt getUpperBounds() { + exists( + QlBuiltins::BigInt lLower, QlBuiltins::BigInt lUpper, QlBuiltins::BigInt rLower, + QlBuiltins::BigInt rUpper + | lLower = getFullyConvertedLowerBounds(this.getLeftOperand()) and lUpper = getFullyConvertedUpperBounds(this.getLeftOperand()) and rLower = getFullyConvertedLowerBounds(this.getRightOperand()) and @@ -236,7 +250,7 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr { rLower <= rUpper | if - lLower < 0 + lLower < 0.toBigInt() or not ( isValidShiftExprShift(rLower, this.getLeftOperand()) and @@ -253,7 +267,7 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr { // If necessary, we may be able to improve this bound in the future if canLShiftOverflow(lUpper, rUpper, exprMaxVal(this)) then result = exprMaxVal(this) - else result = lUpper.bitShiftLeft(rUpper) + else result = lUpper.bitShiftLeft(rUpper.toInt()) ) } diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/StrlenLiteralRangeExpr.qll b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/StrlenLiteralRangeExpr.qll index f301263d0e38..2c2ad03f42ef 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/StrlenLiteralRangeExpr.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/StrlenLiteralRangeExpr.qll @@ -10,9 +10,13 @@ class StrlenLiteralRangeExpr extends SimpleRangeAnalysisExpr, FunctionCall { this.getTarget().hasGlobalOrStdName("strlen") and this.getArgument(0).isConstant() } - override int getLowerBounds() { result = this.getArgument(0).getValue().length() } + override QlBuiltins::BigInt getLowerBounds() { + result = this.getArgument(0).getValue().length().toBigInt() + } - override int getUpperBounds() { result = this.getArgument(0).getValue().length() } + override QlBuiltins::BigInt getUpperBounds() { + result = this.getArgument(0).getValue().length().toBigInt() + } override predicate dependsOnChild(Expr e) { none() } } diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll index 32b4d2a4fba6..5c8051b529e1 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions/SubtractSelf.qll @@ -7,9 +7,9 @@ private class SelfSub extends SimpleRangeAnalysisExpr, SubExpr { this.getRightOperand().getExplicitlyConverted().(VariableAccess).getTarget() } - override float getLowerBounds() { result = 0 } + override QlBuiltins::BigInt getLowerBounds() { result = 0.toBigInt() } - override float getUpperBounds() { result = 0 } + override QlBuiltins::BigInt getUpperBounds() { result = 0.toBigInt() } override predicate dependsOnChild(Expr child) { none() } } diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll b/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll index 51d2e294b36e..c6be50c19831 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/Printf.qll @@ -356,10 +356,8 @@ class FormattingFunctionCall extends Expr { * `f` is assumed to be nonnegative. */ bindingset[f] -private int lengthInBase10(float f) { - f = 0 and result = 1 - or - result = f.log10().floor() + 1 +private QlBuiltins::BigInt lengthInBase10(QlBuiltins::BigInt f) { + result = f.toString().length().toBigInt() } pragma[nomagic] @@ -373,7 +371,7 @@ private BufferWriteEstimationReason getEstimationReasonForIntegralExpression(Exp // expr should already be given as getFullyConverted if upperBound(expr) < exprMaxVal(expr) and - (exprMinVal(expr) >= 0 or lowerBound(expr) > exprMinVal(expr)) + (exprMinVal(expr) >= 0.toBigInt() or lowerBound(expr) > exprMinVal(expr)) then // next we check whether the estimate may have been widened if upperBoundMayBeWidened(expr) @@ -1174,31 +1172,32 @@ class FormatLiteral extends Literal instanceof StringLiteral { or this.getConversionChar(n).toLowerCase() = ["d", "i"] and // e.g. -2^31 = "-2147483648" - exists(float typeBasedBound, float valueBasedBound | + exists(QlBuiltins::BigInt typeBasedBound, QlBuiltins::BigInt valueBasedBound | // The first case handles length sub-specifiers // Subtract one in the exponent because one bit is for the sign. // Add 1 to account for the possible sign in the output. typeBasedBound = - 1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1)) and + 1.toBigInt() + + lengthInBase10(2.toBigInt().pow(this.getIntegralDisplayType(n).getSize() * 8 - 1)) and // The second case uses range analysis to deduce a length that's shorter than the length // of the number -2^31. - exists(Expr arg, float lower, float upper | + exists(Expr arg, QlBuiltins::BigInt lower, QlBuiltins::BigInt upper | arg = this.getUse().getConversionArgument(n) and lower = lowerBound(arg.getFullyConverted()) and upper = upperBound(arg.getFullyConverted()) | valueBasedBound = - max(int cand | + max(QlBuiltins::BigInt cand | // Include the sign bit in the length if it can be negative ( - if lower < 0 - then cand = 1 + lengthInBase10(lower.abs()) + if lower < 0.toBigInt() + then cand = 1.toBigInt() + lengthInBase10(lower.abs()) else cand = lengthInBase10(lower) ) or ( - if upper < 0 - then cand = 1 + lengthInBase10(upper.abs()) + if upper < 0.toBigInt() + then cand = 1.toBigInt() + lengthInBase10(upper.abs()) else cand = lengthInBase10(upper) ) ) and @@ -1206,26 +1205,28 @@ class FormatLiteral extends Literal instanceof StringLiteral { // to detect non-trivial range analysis without taking into account up-casting reason = getEstimationReasonForIntegralExpression(arg) ) and - len = valueBasedBound.minimum(typeBasedBound) + len = valueBasedBound.minimum(typeBasedBound).toInt() ) or this.getConversionChar(n).toLowerCase() = "u" and // e.g. 2^32 - 1 = "4294967295" - exists(float typeBasedBound, float valueBasedBound | + exists(QlBuiltins::BigInt typeBasedBound, QlBuiltins::BigInt valueBasedBound | // The first case handles length sub-specifiers - typeBasedBound = lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8) - 1) and + typeBasedBound = + lengthInBase10(2.toBigInt().pow(this.getIntegralDisplayType(n).getSize() * 8) - + 1.toBigInt()) and // The second case uses range analysis to deduce a length that's shorter than // the length of the number 2^31 - 1. - exists(Expr arg, float lower, float upper | + exists(Expr arg, QlBuiltins::BigInt lower, QlBuiltins::BigInt upper | arg = this.getUse().getConversionArgument(n) and lower = lowerBound(arg.getFullyConverted()) and upper = upperBound(arg.getFullyConverted()) | valueBasedBound = - lengthInBase10(max(float cand | + lengthInBase10(max(QlBuiltins::BigInt cand | // If lower can be negative we use `(unsigned)-1` as the candidate value. - lower < 0 and - cand = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8) + lower < 0.toBigInt() and + cand = 2.toBigInt().pow(any(IntType t | t.isUnsigned()).getSize() * 8) or cand = upper )) and @@ -1233,7 +1234,7 @@ class FormatLiteral extends Literal instanceof StringLiteral { // to detect non-trivial range analysis without taking into account up-casting reason = getEstimationReasonForIntegralExpression(arg) ) and - len = valueBasedBound.minimum(typeBasedBound) + len = valueBasedBound.minimum(typeBasedBound).toInt() ) or this.getConversionChar(n).toLowerCase() = "x" and @@ -1250,7 +1251,10 @@ class FormatLiteral extends Literal instanceof StringLiteral { digits = 2 * t.getSize() ) ) and - exists(Expr arg, float lower, float upper, float typeLower, float typeUpper | + exists( + Expr arg, QlBuiltins::BigInt lower, QlBuiltins::BigInt upper, + QlBuiltins::BigInt typeLower, QlBuiltins::BigInt typeUpper + | arg = this.getUse().getConversionArgument(n) and lower = lowerBound(arg.getFullyConverted()) and upper = upperBound(arg.getFullyConverted()) and @@ -1260,10 +1264,10 @@ class FormatLiteral extends Literal instanceof StringLiteral { valueBasedBound = lengthInBase16(max(float cand | // If lower can be negative we use `(unsigned)-1` as the candidate value. - lower < 0 and + lower < 0.toBigInt() and cand = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8) or - cand = upper + cand = upper.toString().toFloat() )) and ( if lower > typeLower or upper < typeUpper diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/PointlessComparison.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/PointlessComparison.qll index 47289c7552b9..b90b842666b5 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/PointlessComparison.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/PointlessComparison.qll @@ -6,10 +6,10 @@ 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()) } +private QlBuiltins::BigInt 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()) } +private QlBuiltins::BigInt upperBoundFC(Expr expr) { result = upperBound(expr.getFullyConverted()) } /** * Describes which side of a pointless comparison is known to be smaller. @@ -33,7 +33,9 @@ newtype SmallSide = * 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) { +private predicate alwaysLT( + ComparisonOperation cmp, QlBuiltins::BigInt left, QlBuiltins::BigInt right, SmallSide ss +) { ss = LeftIsSmaller() and left = upperBoundFC(cmp.getLeftOperand()) and right = lowerBoundFC(cmp.getRightOperand()) and @@ -49,19 +51,13 @@ private predicate alwaysLT(ComparisonOperation cmp, float left, float right, Sma * 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) { +private predicate alwaysLE( + ComparisonOperation cmp, QlBuiltins::BigInt left, QlBuiltins::BigInt 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 + left <= right } /** @@ -73,7 +69,9 @@ private predicate alwaysLE(ComparisonOperation cmp, float left, float right, Sma * 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) { +private predicate alwaysGT( + ComparisonOperation cmp, QlBuiltins::BigInt left, QlBuiltins::BigInt right, SmallSide ss +) { ss = RightIsSmaller() and left = lowerBoundFC(cmp.getLeftOperand()) and right = upperBoundFC(cmp.getRightOperand()) and @@ -89,19 +87,13 @@ private predicate alwaysGT(ComparisonOperation cmp, float left, float right, Sma * 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) { +private predicate alwaysGE( + ComparisonOperation cmp, QlBuiltins::BigInt left, QlBuiltins::BigInt 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 + left >= right } /** @@ -123,7 +115,8 @@ private predicate alwaysGE(ComparisonOperation cmp, float left, float right, Sma * `pointlessComparison(x < y, 9, 7, false, RightIsSmaller)` holds. */ predicate pointlessComparison( - ComparisonOperation cmp, float left, float right, boolean value, SmallSide ss + ComparisonOperation cmp, QlBuiltins::BigInt left, QlBuiltins::BigInt right, boolean value, + SmallSide ss ) { alwaysLT(cmp.(LTExpr), left, right, ss) and value = true or @@ -164,7 +157,8 @@ predicate pointlessComparison( * } */ predicate reachablePointlessComparison( - ComparisonOperation cmp, float left, float right, boolean value, SmallSide ss + ComparisonOperation cmp, QlBuiltins::BigInt left, QlBuiltins::BigInt right, boolean value, + SmallSide ss ) { pointlessComparison(cmp, left, right, value, ss) and // Reachable according to control flow analysis. diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll index eb167a09c4c4..0b11a25bc3d9 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll @@ -235,9 +235,9 @@ predicate eqZeroWithNegate(Expr cmp, Expr a, boolean isEQ, boolean branch) { * number. This takes into account the associativity, commutativity and * distributivity of arithmetic operations. */ -predicate linearAccess(Expr expr, VariableAccess v, float p, float q) { +predicate linearAccess(Expr expr, VariableAccess v, QlBuiltins::BigInt p, QlBuiltins::BigInt q) { // Exclude 0 and NaN. - (p < 0 or p > 0) and + (p < 0.toBigInt() or p > 0.toBigInt()) and linearAccessImpl(expr, v, p, q) } @@ -246,34 +246,36 @@ predicate linearAccess(Expr expr, VariableAccess v, float p, float q) { * This takes into account the associativity, commutativity and * distributivity of arithmetic operations. */ -private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q) { +private predicate linearAccessImpl( + Expr expr, VariableAccess v, QlBuiltins::BigInt p, QlBuiltins::BigInt q +) { // Base case - expr = v and p = 1.0 and q = 0.0 + expr = v and p = 1.toBigInt() and q = 0.toBigInt() or - expr.(ReferenceDereferenceExpr).getExpr() = v and p = 1.0 and q = 0.0 + expr.(ReferenceDereferenceExpr).getExpr() = v and p = 1.toBigInt() and q = 0.toBigInt() or // a+(p*v+b) == p*v + (a+b) - exists(AddExpr addExpr, float a, float b | + exists(AddExpr addExpr, QlBuiltins::BigInt a, QlBuiltins::BigInt b | addExpr.getLeftOperand().isConstant() and - a = addExpr.getLeftOperand().getFullyConverted().getValue().toFloat() and + a = parseAsBigInt(addExpr.getLeftOperand().getFullyConverted().getValue()) and linearAccess(addExpr.getRightOperand(), v, p, b) and expr = addExpr and q = a + b ) or // (p*v+a)+b == p*v + (a+b) - exists(AddExpr addExpr, float a, float b | + exists(AddExpr addExpr, QlBuiltins::BigInt a, QlBuiltins::BigInt b | addExpr.getRightOperand().isConstant() and - b = addExpr.getRightOperand().getFullyConverted().getValue().toFloat() and + b = parseAsBigInt(addExpr.getRightOperand().getFullyConverted().getValue()) and linearAccess(addExpr.getLeftOperand(), v, p, a) and expr = addExpr and q = a + b ) or // a-(m*v+b) == -m*v + (a-b) - exists(SubExpr subExpr, float a, float b, float m | + exists(SubExpr subExpr, QlBuiltins::BigInt a, QlBuiltins::BigInt b, QlBuiltins::BigInt m | subExpr.getLeftOperand().isConstant() and - a = subExpr.getLeftOperand().getFullyConverted().getValue().toFloat() and + a = parseAsBigInt(subExpr.getLeftOperand().getFullyConverted().getValue()) and linearAccess(subExpr.getRightOperand(), v, m, b) and expr = subExpr and p = -m and @@ -281,9 +283,9 @@ private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q ) or // (p*v+a)-b == p*v + (a-b) - exists(SubExpr subExpr, float a, float b | + exists(SubExpr subExpr, QlBuiltins::BigInt a, QlBuiltins::BigInt b | subExpr.getRightOperand().isConstant() and - b = subExpr.getRightOperand().getFullyConverted().getValue().toFloat() and + b = parseAsBigInt(subExpr.getRightOperand().getFullyConverted().getValue()) and linearAccess(subExpr.getLeftOperand(), v, p, a) and expr = subExpr and q = a - b @@ -314,7 +316,7 @@ private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q ) or // -(a*v+b) == -a*v + (-b) - exists(UnaryMinusExpr unaryMinusExpr, float a, float b | + exists(UnaryMinusExpr unaryMinusExpr, QlBuiltins::BigInt a, QlBuiltins::BigInt b | linearAccess(unaryMinusExpr.getOperand().getFullyConverted(), v, a, b) and expr = unaryMinusExpr and p = -a and @@ -322,9 +324,9 @@ private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q ) or // m*(a*v+b) == (m*a)*v + (m*b) - exists(MulExpr mulExpr, float a, float b, float m | + exists(MulExpr mulExpr, QlBuiltins::BigInt a, QlBuiltins::BigInt b, QlBuiltins::BigInt m | mulExpr.getLeftOperand().isConstant() and - m = mulExpr.getLeftOperand().getFullyConverted().getValue().toFloat() and + m = parseAsBigInt(mulExpr.getLeftOperand().getFullyConverted().getValue()) and linearAccess(mulExpr.getRightOperand(), v, a, b) and expr = mulExpr and p = m * a and @@ -332,9 +334,9 @@ private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q ) or // (a*v+b)*m == (m*a)*v + (m*b) - exists(MulExpr mulExpr, float a, float b, float m | + exists(MulExpr mulExpr, QlBuiltins::BigInt a, QlBuiltins::BigInt b, QlBuiltins::BigInt m | mulExpr.getRightOperand().isConstant() and - m = mulExpr.getRightOperand().getFullyConverted().getValue().toFloat() and + m = parseAsBigInt(mulExpr.getRightOperand().getFullyConverted().getValue()) and linearAccess(mulExpr.getLeftOperand(), v, a, b) and expr = mulExpr and p = m * a and @@ -368,13 +370,13 @@ predicate cmpWithLinearBound( RelationDirection direction, // Is this a lower or an upper bound? boolean branch // Which control-flow branch is this bound valid on? ) { - exists(Expr lhs, float p, RelationDirection dir | + exists(Expr lhs, QlBuiltins::BigInt p, RelationDirection dir | linearAccess(lhs, v, p, _) and relOpWithSwapAndNegate(guard, lhs, _, dir, _, branch) and ( - p > 0 and direction = dir + p > 0.toBigInt() and direction = dir or - p < 0 and direction = negateDirection(dir) + p < 0.toBigInt() and direction = negateDirection(dir) ) ) or @@ -391,23 +393,23 @@ predicate cmpWithLinearBound( * For example, if `t` is a signed 32-bit type then holds if `lb` is * `-2^31` and `ub` is `2^31 - 1`. */ -private predicate typeBounds(ArithmeticType t, float lb, float ub) { - exists(IntegralType integralType, float limit | - integralType = t and limit = 2.pow(8 * integralType.getSize()) +private predicate typeBounds(ArithmeticType t, QlBuiltins::BigInt lb, QlBuiltins::BigInt ub) { + exists(IntegralType integralType, QlBuiltins::BigInt limit | + integralType = t and limit = 2.toBigInt().pow(8 * integralType.getSize()) | if integralType instanceof BoolType - then lb = 0 and ub = 1 + then lb = 0.toBigInt() and ub = 1.toBigInt() else if integralType.isSigned() then ( - lb = -(limit / 2) and ub = (limit / 2) - 1 + lb = -(limit / 2.toBigInt()) and ub = (limit / 2.toBigInt()) - 1.toBigInt() ) else ( - lb = 0 and ub = limit - 1 + lb = 0.toBigInt() and ub = limit - 1.toBigInt() ) ) or // This covers all floating point types. The range is (-Inf, +Inf). - t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0 + t instanceof FloatingPointType and lb = -infinityAsBigInt() and ub = infinityAsBigInt() } private Type stripReference(Type t) { @@ -423,7 +425,7 @@ Type getVariableRangeType(StackVariable v) { result = stripReference(v.getUnspec * For example, if `t` is a signed 32-bit type then the result is * `-2^31`. */ -float typeLowerBound(Type t) { typeBounds(stripReference(t), result, _) } +QlBuiltins::BigInt typeLowerBound(Type t) { typeBounds(stripReference(t), result, _) } /** * Gets the upper bound for the unspecified type `t`. @@ -431,7 +433,7 @@ float typeLowerBound(Type t) { typeBounds(stripReference(t), result, _) } * For example, if `t` is a signed 32-bit type then the result is * `2^31 - 1`. */ -float typeUpperBound(Type t) { typeBounds(stripReference(t), _, result) } +QlBuiltins::BigInt typeUpperBound(Type t) { typeBounds(stripReference(t), _, result) } /** * Gets the minimum value that this expression could represent, based on @@ -444,7 +446,7 @@ float typeUpperBound(Type t) { typeBounds(stripReference(t), _, result) } * `exprMinVal(expr)` you will normally want to call * `exprMinVal(expr.getFullyConverted())`. */ -float exprMinVal(Expr expr) { result = typeLowerBound(expr.getUnspecifiedType()) } +QlBuiltins::BigInt exprMinVal(Expr expr) { result = typeLowerBound(expr.getUnspecifiedType()) } /** * Gets the maximum value that this expression could represent, based on @@ -457,7 +459,7 @@ float exprMinVal(Expr expr) { result = typeLowerBound(expr.getUnspecifiedType()) * `exprMaxVal(expr)` you will normally want to call * `exprMaxVal(expr.getFullyConverted())`. */ -float exprMaxVal(Expr expr) { result = typeUpperBound(expr.getUnspecifiedType()) } +QlBuiltins::BigInt exprMaxVal(Expr expr) { result = typeUpperBound(expr.getUnspecifiedType()) } /** * Gets the minimum value that this variable could represent, based on @@ -466,7 +468,7 @@ float exprMaxVal(Expr expr) { result = typeUpperBound(expr.getUnspecifiedType()) * For example, if `v` has a signed 32-bit type then the result is * `-2^31`. */ -float varMinVal(Variable v) { result = typeLowerBound(v.getUnspecifiedType()) } +QlBuiltins::BigInt varMinVal(Variable v) { result = typeLowerBound(v.getUnspecifiedType()) } /** * Gets the maximum value that this variable could represent, based on @@ -475,4 +477,67 @@ float varMinVal(Variable v) { result = typeLowerBound(v.getUnspecifiedType()) } * For example, if `v` has a signed 32-bit type then the result is * `2^31 - 1`. */ -float varMaxVal(Variable v) { result = typeUpperBound(v.getUnspecifiedType()) } +QlBuiltins::BigInt varMaxVal(Variable v) { result = typeUpperBound(v.getUnspecifiedType()) } + +/** + * Magic number larger than the largest positive finite double. + */ +QlBuiltins::BigInt infinityAsBigInt() { result = 1.toBigInt().bitShiftLeft(1024) } + +bindingset[s] +QlBuiltins::BigInt parseAsBigInt(string s) { + result = s.toBigInt() + or + s.toFloat() = 1.0 / 0.0 and result = infinityAsBigInt() + or + s.toFloat() = -(1.0 / 0.0) and result = -infinityAsBigInt() + or + exists(QlBuiltins::BigInt coeff, int base10exp | parseFiniteAsBigInt(s, coeff, base10exp) | + if base10exp < 0 + then result = coeff / 10.toBigInt().pow(-base10exp) + else result = coeff * 10.toBigInt().pow(base10exp) + ) +} + +bindingset[s] +private predicate parseFiniteAsBigInt(string s, QlBuiltins::BigInt coeff, int base10exp) { + exists(string t | s = "+" + t | parseUnsignedAsBigInt(t, coeff, base10exp)) + or + exists(string t | s = "-" + t | parseUnsignedAsBigInt(t, -coeff, base10exp)) + or + parseUnsignedAsBigInt(s, coeff, base10exp) +} + +bindingset[s] +private predicate parseUnsignedAsBigInt(string s, QlBuiltins::BigInt coeff, int base10exp) { + exists(string beforeE, int base10expAfterE, int base10expBeforeE | + beforeE = s.toUpperCase().splitAt("E", 0) and + base10expAfterE = parseSignedInt(s.toUpperCase().splitAt("E", 1)) and + parseUnsignedDecimalAsBigInt(beforeE, coeff, base10expBeforeE) and + base10exp = base10expBeforeE + base10expAfterE + ) + or + exists(string beforeDot, string afterDot | + beforeDot = s.splitAt(".", 0) and + afterDot = s.splitAt(".", 1) and + coeff = (beforeDot + afterDot).toBigInt() and + base10exp = -afterDot.length() + ) +} + +bindingset[s] +private predicate parseUnsignedDecimalAsBigInt(string s, QlBuiltins::BigInt coeff, int base10exp) { + exists(string beforeDot, string afterDot | + beforeDot = s.splitAt(".", 0) and + afterDot = s.splitAt(".", 1) and + coeff = (beforeDot + afterDot).toBigInt() and + base10exp = -afterDot.length() + ) +} + +bindingset[s] +private int parseSignedInt(string s) { + exists(string t | s = "+" + t | result = t.toInt()) + or + result = s.toInt() +} diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 1ce7a6a4f5a8..4526ab6044ce 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -60,37 +60,37 @@ private import NanAnalysis * bounds to the set if it helps on specific examples and does not make * performance dramatically worse on large codebases, such as libreoffice. */ -private float wideningLowerBounds(ArithmeticType t) { - result = 2.0 or - result = 1.0 or - result = 0.0 or - result = -1.0 or - result = -2.0 or - result = -8.0 or - result = -16.0 or - result = -128.0 or - result = -256.0 or - result = -32768.0 or - result = -65536.0 or +private QlBuiltins::BigInt wideningLowerBounds(ArithmeticType t) { + result = 2.toBigInt() or + result = 1.toBigInt() or + result = 0.toBigInt() or + result = -1.toBigInt() or + result = -2.toBigInt() or + result = -8.toBigInt() or + result = -16.toBigInt() or + result = -128.toBigInt() or + result = -256.toBigInt() or + result = -32768.toBigInt() or + result = -65536.toBigInt() or result = typeLowerBound(t) or - result = -(1.0 / 0.0) // -Inf + result = -infinityAsBigInt() // -Inf } /** See comment for `wideningLowerBounds`, above. */ -private float wideningUpperBounds(ArithmeticType t) { - result = -2.0 or - result = -1.0 or - result = 0.0 or - result = 1.0 or - result = 2.0 or - result = 7.0 or - result = 15.0 or - result = 127.0 or - result = 255.0 or - result = 32767.0 or - result = 65535.0 or +private QlBuiltins::BigInt wideningUpperBounds(ArithmeticType t) { + result = -2.toBigInt() or + result = -1.toBigInt() or + result = 0.toBigInt() or + result = 1.toBigInt() or + result = 2.toBigInt() or + result = 7.toBigInt() or + result = 15.toBigInt() or + result = 127.toBigInt() or + result = 255.toBigInt() or + result = 32767.toBigInt() or + result = 65535.toBigInt() or result = typeUpperBound(t) or - result = 1.0 / 0.0 // +Inf + result = infinityAsBigInt() // +Inf } /** @@ -165,19 +165,24 @@ float safeFloor(float v) { /** A `MulExpr` where exactly one operand is constant. */ private class MulByConstantExpr extends MulExpr { - float constant; + float floatConstant; + QlBuiltins::BigInt bigIntConstant; Expr operand; MulByConstantExpr() { exists(Expr constantExpr | this.hasOperands(constantExpr, operand) and - constant = getValue(constantExpr.getFullyConverted()).toFloat() and + floatConstant = getValue(constantExpr.getFullyConverted()).toFloat() and + bigIntConstant = parseAsBigInt(getValue(constantExpr.getFullyConverted())) and not exists(getValue(operand.getFullyConverted()).toFloat()) ) } /** Gets the value of the constant operand. */ - float getConstant() { result = constant } + float getFloatConstant() { result = floatConstant } + + /** Gets the value of the constant operand. */ + QlBuiltins::BigInt getBigIntConstant() { result = bigIntConstant } /** Gets the non-constant operand. */ Expr getOperand() { result = operand } @@ -196,48 +201,58 @@ private class UnsignedMulExpr extends MulExpr { * Holds if `expr` is effectively a multiplication of `operand` with the * positive constant `positive`. */ -private predicate effectivelyMultipliesByPositive(Expr expr, Expr operand, float positive) { +private predicate effectivelyMultipliesByPositive( + Expr expr, Expr operand, QlBuiltins::BigInt positive +) { operand = expr.(MulByConstantExpr).getOperand() and - positive = expr.(MulByConstantExpr).getConstant() and - positive >= 0.0 // includes positive zero + positive = expr.(MulByConstantExpr).getBigIntConstant() and + expr.(MulByConstantExpr).getFloatConstant() >= 0.0 // includes positive zero or operand = expr.(UnaryPlusExpr).getOperand() and - positive = 1.0 + positive = 1.toBigInt() or operand = expr.(CommaExpr).getRightOperand() and - positive = 1.0 + positive = 1.toBigInt() or operand = expr.(StmtExpr).getResultExpr() and - positive = 1.0 + positive = 1.toBigInt() } /** * Holds if `expr` is effectively a multiplication of `operand` with the * negative constant `negative`. */ -private predicate effectivelyMultipliesByNegative(Expr expr, Expr operand, float negative) { +private predicate effectivelyMultipliesByNegative( + Expr expr, Expr operand, QlBuiltins::BigInt negative +) { operand = expr.(MulByConstantExpr).getOperand() and - negative = expr.(MulByConstantExpr).getConstant() and - negative < 0.0 // includes negative zero + negative = expr.(MulByConstantExpr).getBigIntConstant() and + expr.(MulByConstantExpr).getFloatConstant() < 0.0 // includes negative zero or operand = expr.(UnaryMinusExpr).getOperand() and - negative = -1.0 + negative = -1.toBigInt() } private class AssignMulByConstantExpr extends AssignMulExpr { - float constant; + float floatConstant; + QlBuiltins::BigInt bigIntConstant; - AssignMulByConstantExpr() { constant = getValue(this.getRValue().getFullyConverted()).toFloat() } + AssignMulByConstantExpr() { + floatConstant = getValue(this.getRValue().getFullyConverted()).toFloat() and + bigIntConstant = parseAsBigInt(getValue(this.getRValue().getFullyConverted())) + } + + float getFloatConstant() { result = floatConstant } - float getConstant() { result = constant } + QlBuiltins::BigInt getBigIntConstant() { result = bigIntConstant } } private class AssignMulByPositiveConstantExpr extends AssignMulByConstantExpr { - AssignMulByPositiveConstantExpr() { constant >= 0.0 } + AssignMulByPositiveConstantExpr() { floatConstant >= 0.0 } } private class AssignMulByNegativeConstantExpr extends AssignMulByConstantExpr { - AssignMulByNegativeConstantExpr() { constant < 0.0 } + AssignMulByNegativeConstantExpr() { floatConstant < 0.0 } } private class UnsignedAssignMulExpr extends AssignMulExpr { @@ -538,55 +553,6 @@ private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) { def.(SimpleRangeAnalysisDefinition).hasRangeInformationFor(v) } -/** - * Computes a normal form of `x` where -0.0 has changed to +0.0. This can be - * needed on the lesser side of a floating-point comparison or on both sides of - * a floating point equality because QL does not follow IEEE in floating-point - * comparisons but instead defines -0.0 to be less than and distinct from 0.0. - */ -bindingset[x] -private float normalizeFloatUp(float x) { result = x + 0.0 } - -/** - * Computes `x + y`, rounded towards +Inf. This is the general case where both - * `x` and `y` may be large numbers. - */ -bindingset[x, y] -private float addRoundingUp(float x, float y) { - if normalizeFloatUp((x + y) - x) < y or normalizeFloatUp((x + y) - y) < x - then result = (x + y).nextUp() - else result = (x + y) -} - -/** - * Computes `x + y`, rounded towards -Inf. This is the general case where both - * `x` and `y` may be large numbers. - */ -bindingset[x, y] -private float addRoundingDown(float x, float y) { - if (x + y) - x > normalizeFloatUp(y) or (x + y) - y > normalizeFloatUp(x) - then result = (x + y).nextDown() - else result = (x + y) -} - -/** - * Computes `x + small`, rounded towards +Inf, where `small` is a small - * constant. - */ -bindingset[x, small] -private float addRoundingUpSmall(float x, float small) { - if (x + small) - x < small then result = (x + small).nextUp() else result = (x + small) -} - -/** - * Computes `x + small`, rounded towards -Inf, where `small` is a small - * constant. - */ -bindingset[x, small] -private float addRoundingDownSmall(float x, float small) { - if (x + small) - x > small then result = (x + small).nextDown() else result = (x + small) -} - private predicate lowerBoundableExpr(Expr expr) { analyzableExpr(expr) and getUpperBoundsImpl(expr) <= exprMaxVal(expr) and @@ -610,22 +576,22 @@ private predicate lowerBoundableExpr(Expr expr) { * Note: most callers should use `getFullyConvertedLowerBounds` rather than * this predicate. */ -private float getTruncatedLowerBounds(Expr expr) { +private QlBuiltins::BigInt getTruncatedLowerBounds(Expr expr) { // If the expression evaluates to a constant, then there is no // need to call getLowerBoundsImpl. analyzableExpr(expr) and - result = getValue(expr).toFloat() + result = parseAsBigInt(getValue(expr)) or // Some of the bounds computed by getLowerBoundsImpl might // overflow, so we replace invalid bounds with exprMinVal. - exists(float newLB | newLB = normalizeFloatUp(getLowerBoundsImpl(expr)) | + exists(QlBuiltins::BigInt newLB | newLB = getLowerBoundsImpl(expr) | if exprMinVal(expr) <= newLB and newLB <= exprMaxVal(expr) then // Apply widening where we might get a combinatorial explosion. if isRecursiveBinary(expr) then result = - max(float widenLB | + max(QlBuiltins::BigInt widenLB | widenLB = wideningLowerBounds(expr.getUnspecifiedType()) and not widenLB > newLB ) @@ -638,7 +604,7 @@ private float getTruncatedLowerBounds(Expr expr) { // lower bound is exprMinVal. analyzableExpr(expr) and exprMightOverflowPositively(expr) and - not result = getValue(expr).toFloat() and + not result = parseAsBigInt(getValue(expr)) and result = exprMinVal(expr) or // The expression is not analyzable, so its lower bound is @@ -666,25 +632,25 @@ private float getTruncatedLowerBounds(Expr expr) { * Note: most callers should use `getFullyConvertedUpperBounds` rather than * this predicate. */ -private float getTruncatedUpperBounds(Expr expr) { +private QlBuiltins::BigInt getTruncatedUpperBounds(Expr expr) { if analyzableExpr(expr) then // If the expression evaluates to a constant, then there is no // need to call getUpperBoundsImpl. - if exists(getValue(expr).toFloat()) - then result = getValue(expr).toFloat() + if exists(parseAsBigInt(getValue(expr))) + then result = parseAsBigInt(getValue(expr)) else ( // Some of the bounds computed by `getUpperBoundsImpl` // might overflow, so we replace invalid bounds with // `exprMaxVal`. - exists(float newUB | newUB = normalizeFloatUp(getUpperBoundsImpl(expr)) | + exists(QlBuiltins::BigInt newUB | newUB = getUpperBoundsImpl(expr) | if exprMinVal(expr) <= newUB and newUB <= exprMaxVal(expr) then // Apply widening where we might get a combinatorial explosion. if isRecursiveBinary(expr) then result = - min(float widenUB | + min(QlBuiltins::BigInt widenUB | widenUB = wideningUpperBounds(expr.getUnspecifiedType()) and not widenUB < newUB ) @@ -706,15 +672,15 @@ private float getTruncatedUpperBounds(Expr expr) { } /** Only to be called by `getTruncatedLowerBounds`. */ -private float getLowerBoundsImpl(Expr expr) { +private QlBuiltins::BigInt getLowerBoundsImpl(Expr expr) { ( - exists(Expr operand, float operandLow, float positive | + exists(Expr operand, QlBuiltins::BigInt operandLow, QlBuiltins::BigInt positive | effectivelyMultipliesByPositive(expr, operand, positive) and operandLow = getFullyConvertedLowerBounds(operand) and result = positive * operandLow ) or - exists(Expr operand, float operandHigh, float negative | + exists(Expr operand, QlBuiltins::BigInt operandHigh, QlBuiltins::BigInt negative | effectivelyMultipliesByNegative(expr, operand, negative) and operandHigh = getFullyConvertedUpperBounds(operand) and result = negative * operandHigh @@ -733,7 +699,7 @@ private float getLowerBoundsImpl(Expr expr) { // // max (minimum{X}, minimum{Y}) // = minimum { max(x,y) | x in X, y in Y } - exists(float x, float y | + exists(QlBuiltins::BigInt x, QlBuiltins::BigInt y | x = getFullyConvertedLowerBounds(maxExpr.getLeftOperand()) and y = getFullyConvertedLowerBounds(maxExpr.getRightOperand()) and if x >= y then result = x else result = y @@ -745,7 +711,7 @@ private float getLowerBoundsImpl(Expr expr) { expr = condExpr and // Use `boolConversionUpperBound` to determine whether the condition // might evaluate to `true`. - boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1.toBigInt() and result = getFullyConvertedLowerBounds(condExpr.getThen()) ) or @@ -754,25 +720,25 @@ private float getLowerBoundsImpl(Expr expr) { expr = condExpr and // Use `boolConversionLowerBound` to determine whether the condition // might evaluate to `false`. - boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0.toBigInt() and result = getFullyConvertedLowerBounds(condExpr.getElse()) ) or - exists(AddExpr addExpr, float xLow, float yLow | + exists(AddExpr addExpr, QlBuiltins::BigInt xLow, QlBuiltins::BigInt yLow | expr = addExpr and xLow = getFullyConvertedLowerBounds(addExpr.getLeftOperand()) and yLow = getFullyConvertedLowerBounds(addExpr.getRightOperand()) and - result = addRoundingDown(xLow, yLow) + result = xLow + yLow ) or - exists(SubExpr subExpr, float xLow, float yHigh | + exists(SubExpr subExpr, QlBuiltins::BigInt xLow, QlBuiltins::BigInt yHigh | expr = subExpr and xLow = getFullyConvertedLowerBounds(subExpr.getLeftOperand()) and yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and - result = addRoundingDown(xLow, -yHigh) + result = xLow - yHigh ) or - exists(UnsignedMulExpr mulExpr, float xLow, float yLow | + exists(UnsignedMulExpr mulExpr, QlBuiltins::BigInt xLow, QlBuiltins::BigInt yLow | expr = mulExpr and xLow = getFullyConvertedLowerBounds(mulExpr.getLeftOperand()) and yLow = getFullyConvertedLowerBounds(mulExpr.getRightOperand()) and @@ -784,49 +750,49 @@ private float getLowerBoundsImpl(Expr expr) { result = getFullyConvertedLowerBounds(assign.getRValue()) ) or - exists(AssignAddExpr addExpr, float xLow, float yLow | + exists(AssignAddExpr addExpr, QlBuiltins::BigInt xLow, QlBuiltins::BigInt yLow | expr = addExpr and xLow = getFullyConvertedLowerBounds(addExpr.getLValue()) and yLow = getFullyConvertedLowerBounds(addExpr.getRValue()) and - result = addRoundingDown(xLow, yLow) + result = xLow + yLow ) or - exists(AssignSubExpr subExpr, float xLow, float yHigh | + exists(AssignSubExpr subExpr, QlBuiltins::BigInt xLow, QlBuiltins::BigInt yHigh | expr = subExpr and xLow = getFullyConvertedLowerBounds(subExpr.getLValue()) and yHigh = getFullyConvertedUpperBounds(subExpr.getRValue()) and - result = addRoundingDown(xLow, -yHigh) + result = xLow - yHigh ) or - exists(UnsignedAssignMulExpr mulExpr, float xLow, float yLow | + exists(UnsignedAssignMulExpr mulExpr, QlBuiltins::BigInt xLow, QlBuiltins::BigInt yLow | expr = mulExpr and xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and yLow = getFullyConvertedLowerBounds(mulExpr.getRValue()) and result = xLow * yLow ) or - exists(AssignMulByPositiveConstantExpr mulExpr, float xLow | + exists(AssignMulByPositiveConstantExpr mulExpr, QlBuiltins::BigInt xLow | expr = mulExpr and xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and - result = xLow * mulExpr.getConstant() + result = xLow * mulExpr.getBigIntConstant() ) or - exists(AssignMulByNegativeConstantExpr mulExpr, float xHigh | + exists(AssignMulByNegativeConstantExpr mulExpr, QlBuiltins::BigInt xHigh | expr = mulExpr and xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and - result = xHigh * mulExpr.getConstant() + result = xHigh * mulExpr.getBigIntConstant() ) or - exists(PrefixIncrExpr incrExpr, float xLow | + exists(PrefixIncrExpr incrExpr, QlBuiltins::BigInt xLow | expr = incrExpr and xLow = getFullyConvertedLowerBounds(incrExpr.getOperand()) and - result = xLow + 1 + result = xLow + 1.toBigInt() ) or - exists(PrefixDecrExpr decrExpr, float xLow | + exists(PrefixDecrExpr decrExpr, QlBuiltins::BigInt xLow | expr = decrExpr and xLow = getFullyConvertedLowerBounds(decrExpr.getOperand()) and - result = addRoundingDownSmall(xLow, -1) + result = xLow - 1.toBigInt() ) or // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their @@ -844,19 +810,21 @@ private float getLowerBoundsImpl(Expr expr) { or exists(RemExpr remExpr | expr = remExpr | // If both inputs are positive then the lower bound is zero. - result = 0 + result = 0.toBigInt() or // If either input could be negative then the output could be // negative. If so, the lower bound of `x%y` is `-abs(y) + 1`, which is // equal to `min(-y + 1,y - 1)`. - exists(float childLB | + exists(QlBuiltins::BigInt childLB | childLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and - not childLB >= 0 + not childLB >= 0.toBigInt() | - result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) - 1 + result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) - 1.toBigInt() or - exists(float rhsUB | rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) | - result = -rhsUB + 1 + exists(QlBuiltins::BigInt rhsUB | + rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) + | + result = -rhsUB + 1.toBigInt() ) ) ) @@ -880,15 +848,15 @@ private float getLowerBoundsImpl(Expr expr) { // unsigned `&` (tighter bounds may exist) exists(UnsignedBitwiseAndExpr andExpr | andExpr = expr and - result = 0.0 + result = 0.toBigInt() ) or // `>>` by a constant - exists(RShiftExpr rsExpr, float left, int right | + exists(RShiftExpr rsExpr, QlBuiltins::BigInt left, int right | rsExpr = expr and left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and - result = safeFloor(left / 2.pow(right)) + result = left / 2.toBigInt().pow(right) ) // Not explicitly modeled by a SimpleRangeAnalysisExpr ) and @@ -902,15 +870,15 @@ private float getLowerBoundsImpl(Expr expr) { } /** Only to be called by `getTruncatedUpperBounds`. */ -private float getUpperBoundsImpl(Expr expr) { +private QlBuiltins::BigInt getUpperBoundsImpl(Expr expr) { ( - exists(Expr operand, float operandHigh, float positive | + exists(Expr operand, QlBuiltins::BigInt operandHigh, QlBuiltins::BigInt positive | effectivelyMultipliesByPositive(expr, operand, positive) and operandHigh = getFullyConvertedUpperBounds(operand) and result = positive * operandHigh ) or - exists(Expr operand, float operandLow, float negative | + exists(Expr operand, QlBuiltins::BigInt operandLow, QlBuiltins::BigInt negative | effectivelyMultipliesByNegative(expr, operand, negative) and operandLow = getFullyConvertedLowerBounds(operand) and result = negative * operandLow @@ -929,7 +897,7 @@ private float getUpperBoundsImpl(Expr expr) { // // min (maximum{X}, maximum{Y}) // = maximum { min(x,y) | x in X, y in Y } - exists(float x, float y | + exists(QlBuiltins::BigInt x, QlBuiltins::BigInt y | x = getFullyConvertedUpperBounds(minExpr.getLeftOperand()) and y = getFullyConvertedUpperBounds(minExpr.getRightOperand()) and if x <= y then result = x else result = y @@ -941,7 +909,7 @@ private float getUpperBoundsImpl(Expr expr) { expr = condExpr and // Use `boolConversionUpperBound` to determine whether the condition // might evaluate to `true`. - boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1.toBigInt() and result = getFullyConvertedUpperBounds(condExpr.getThen()) ) or @@ -950,25 +918,25 @@ private float getUpperBoundsImpl(Expr expr) { expr = condExpr and // Use `boolConversionLowerBound` to determine whether the condition // might evaluate to `false`. - boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0.toBigInt() and result = getFullyConvertedUpperBounds(condExpr.getElse()) ) or - exists(AddExpr addExpr, float xHigh, float yHigh | + exists(AddExpr addExpr, QlBuiltins::BigInt xHigh, QlBuiltins::BigInt yHigh | expr = addExpr and xHigh = getFullyConvertedUpperBounds(addExpr.getLeftOperand()) and yHigh = getFullyConvertedUpperBounds(addExpr.getRightOperand()) and - result = addRoundingUp(xHigh, yHigh) + result = xHigh + yHigh ) or - exists(SubExpr subExpr, float xHigh, float yLow | + exists(SubExpr subExpr, QlBuiltins::BigInt xHigh, QlBuiltins::BigInt yLow | expr = subExpr and xHigh = getFullyConvertedUpperBounds(subExpr.getLeftOperand()) and yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and - result = addRoundingUp(xHigh, -yLow) + result = xHigh - yLow ) or - exists(UnsignedMulExpr mulExpr, float xHigh, float yHigh | + exists(UnsignedMulExpr mulExpr, QlBuiltins::BigInt xHigh, QlBuiltins::BigInt yHigh | expr = mulExpr and xHigh = getFullyConvertedUpperBounds(mulExpr.getLeftOperand()) and yHigh = getFullyConvertedUpperBounds(mulExpr.getRightOperand()) and @@ -980,49 +948,49 @@ private float getUpperBoundsImpl(Expr expr) { result = getFullyConvertedUpperBounds(assign.getRValue()) ) or - exists(AssignAddExpr addExpr, float xHigh, float yHigh | + exists(AssignAddExpr addExpr, QlBuiltins::BigInt xHigh, QlBuiltins::BigInt yHigh | expr = addExpr and xHigh = getFullyConvertedUpperBounds(addExpr.getLValue()) and yHigh = getFullyConvertedUpperBounds(addExpr.getRValue()) and - result = addRoundingUp(xHigh, yHigh) + result = xHigh + yHigh ) or - exists(AssignSubExpr subExpr, float xHigh, float yLow | + exists(AssignSubExpr subExpr, QlBuiltins::BigInt xHigh, QlBuiltins::BigInt yLow | expr = subExpr and xHigh = getFullyConvertedUpperBounds(subExpr.getLValue()) and yLow = getFullyConvertedLowerBounds(subExpr.getRValue()) and - result = addRoundingUp(xHigh, -yLow) + result = xHigh - yLow ) or - exists(UnsignedAssignMulExpr mulExpr, float xHigh, float yHigh | + exists(UnsignedAssignMulExpr mulExpr, QlBuiltins::BigInt xHigh, QlBuiltins::BigInt yHigh | expr = mulExpr and xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and yHigh = getFullyConvertedUpperBounds(mulExpr.getRValue()) and result = xHigh * yHigh ) or - exists(AssignMulByPositiveConstantExpr mulExpr, float xHigh | + exists(AssignMulByPositiveConstantExpr mulExpr, QlBuiltins::BigInt xHigh | expr = mulExpr and xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and - result = xHigh * mulExpr.getConstant() + result = xHigh * mulExpr.getBigIntConstant() ) or - exists(AssignMulByNegativeConstantExpr mulExpr, float xLow | + exists(AssignMulByNegativeConstantExpr mulExpr, QlBuiltins::BigInt xLow | expr = mulExpr and xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and - result = xLow * mulExpr.getConstant() + result = xLow * mulExpr.getBigIntConstant() ) or - exists(PrefixIncrExpr incrExpr, float xHigh | + exists(PrefixIncrExpr incrExpr, QlBuiltins::BigInt xHigh | expr = incrExpr and xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and - result = addRoundingUpSmall(xHigh, 1) + result = xHigh + 1.toBigInt() ) or - exists(PrefixDecrExpr decrExpr, float xHigh | + exists(PrefixDecrExpr decrExpr, QlBuiltins::BigInt xHigh | expr = decrExpr and xHigh = getFullyConvertedUpperBounds(decrExpr.getOperand()) and - result = xHigh - 1 + result = xHigh - 1.toBigInt() ) or // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their operand. @@ -1038,20 +1006,20 @@ private float getUpperBoundsImpl(Expr expr) { result = getFullyConvertedUpperBounds(decrExpr.getOperand()) ) or - exists(RemExpr remExpr, float rhsUB | + exists(RemExpr remExpr, QlBuiltins::BigInt rhsUB | expr = remExpr and rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) | - result = rhsUB - 1 + result = rhsUB - 1.toBigInt() or // If the right hand side could be negative then we need to take its // absolute value. Since `abs(x) = max(-x,x)` this is equivalent to // adding `-rhsLB` to the set of upper bounds. - exists(float rhsLB | + exists(QlBuiltins::BigInt rhsLB | rhsLB = getFullyConvertedLowerBounds(remExpr.getRightOperand()) and - not rhsLB >= 0 + not rhsLB >= 0.toBigInt() | - result = -rhsLB + 1 + result = 1.toBigInt() - rhsLB ) ) or @@ -1072,7 +1040,7 @@ private float getUpperBoundsImpl(Expr expr) { ) or // unsigned `&` (tighter bounds may exist) - exists(UnsignedBitwiseAndExpr andExpr, float left, float right | + exists(UnsignedBitwiseAndExpr andExpr, QlBuiltins::BigInt left, QlBuiltins::BigInt right | andExpr = expr and left = getFullyConvertedUpperBounds(andExpr.getLeftOperand()) and right = getFullyConvertedUpperBounds(andExpr.getRightOperand()) and @@ -1080,11 +1048,11 @@ private float getUpperBoundsImpl(Expr expr) { ) or // `>>` by a constant - exists(RShiftExpr rsExpr, float left, int right | + exists(RShiftExpr rsExpr, QlBuiltins::BigInt left, int right | rsExpr = expr and left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and - result = safeFloor(left / 2.pow(right)) + result = left / 2.toBigInt().pow(right) ) // Not explicitly modeled by a SimpleRangeAnalysisExpr ) and @@ -1121,55 +1089,55 @@ private predicate exprIsUsedAsBool(Expr expr) { * Gets the lower bound of the conversion `(bool)expr`. If we can prove that * the value of `expr` is never 0 then `lb = 1`. Otherwise `lb = 0`. */ -private float boolConversionLowerBound(Expr expr) { +private QlBuiltins::BigInt boolConversionLowerBound(Expr expr) { // Case 1: if the range for `expr` includes the value 0, // then `result = 0`. exprIsUsedAsBool(expr) and - exists(float lb | lb = getTruncatedLowerBounds(expr) and not lb > 0) and - exists(float ub | ub = getTruncatedUpperBounds(expr) and not ub < 0) and - result = 0 + exists(QlBuiltins::BigInt lb | lb = getTruncatedLowerBounds(expr) and not lb > 0.toBigInt()) and + exists(QlBuiltins::BigInt ub | ub = getTruncatedUpperBounds(expr) and not ub < 0.toBigInt()) and + result = 0.toBigInt() or // Case 2a: if the range for `expr` does not include the value 0, // then `result = 1`. - exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) > 0 and result = 1 + exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) > 0.toBigInt() and result = 1.toBigInt() or // Case 2b: if the range for `expr` does not include the value 0, // then `result = 1`. - exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) < 0 and result = 1 + exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) < 0.toBigInt() and result = 1.toBigInt() or // Case 3: the type of `expr` is not arithmetic. For example, it might // be a pointer. - exprIsUsedAsBool(expr) and not exists(exprMinVal(expr)) and result = 0 + exprIsUsedAsBool(expr) and not exists(exprMinVal(expr)) and result = 0.toBigInt() } /** * Gets the upper bound of the conversion `(bool)expr`. If we can prove that * the value of `expr` is always 0 then `ub = 0`. Otherwise `ub = 1`. */ -private float boolConversionUpperBound(Expr expr) { +private QlBuiltins::BigInt boolConversionUpperBound(Expr expr) { // Case 1a: if the upper bound of the operand is <= 0, then the upper // bound might be 0. - exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) <= 0 and result = 0 + exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) <= 0.toBigInt() and result = 0.toBigInt() or // Case 1b: if the upper bound of the operand is not <= 0, then the upper // bound is 1. exprIsUsedAsBool(expr) and - exists(float ub | ub = getTruncatedUpperBounds(expr) and not ub <= 0) and - result = 1 + exists(QlBuiltins::BigInt ub | ub = getTruncatedUpperBounds(expr) and not ub <= 0.toBigInt()) and + result = 1.toBigInt() or // Case 2a: if the lower bound of the operand is >= 0, then the upper // bound might be 0. - exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) >= 0 and result = 0 + exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) >= 0.toBigInt() and result = 0.toBigInt() or // Case 2b: if the lower bound of the operand is not >= 0, then the upper // bound is 1. exprIsUsedAsBool(expr) and - exists(float lb | lb = getTruncatedLowerBounds(expr) and not lb >= 0) and - result = 1 + exists(QlBuiltins::BigInt lb | lb = getTruncatedLowerBounds(expr) and not lb >= 0.toBigInt()) and + result = 1.toBigInt() or // Case 3: the type of `expr` is not arithmetic. For example, it might // be a pointer. - exprIsUsedAsBool(expr) and not exists(exprMaxVal(expr)) and result = 1 + exprIsUsedAsBool(expr) and not exists(exprMaxVal(expr)) and result = 1.toBigInt() } /** @@ -1186,8 +1154,11 @@ private float boolConversionUpperBound(Expr expr) { * In this example, the lower bound of x is 0, but we can * use the guard to deduce that the lower bound is 2 inside the block. */ -private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { - exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB | +private QlBuiltins::BigInt getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { + exists( + VariableAccess access, Expr guard, boolean branch, QlBuiltins::BigInt defLB, + QlBuiltins::BigInt guardLB + | phi.isGuardPhi(v, access, guard, branch) and lowerBoundFromGuard(guard, access, guardLB, branch) and defLB = getFullyConvertedLowerBounds(access) @@ -1196,10 +1167,10 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { if guardLB > defLB then result = guardLB else result = defLB ) or - exists(VariableAccess access, float neConstant, float lower | + exists(VariableAccess access, QlBuiltins::BigInt neConstant, QlBuiltins::BigInt lower | isNEPhi(v, phi, access, neConstant) and lower = getTruncatedLowerBounds(access) and - if lower = neConstant then result = lower + 1 else result = lower + if lower = neConstant then result = lower + 1.toBigInt() else result = lower ) or exists(VariableAccess access | @@ -1211,8 +1182,11 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { } /** See comment for `getPhiLowerBounds`, above. */ -private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { - exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB | +private QlBuiltins::BigInt getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { + exists( + VariableAccess access, Expr guard, boolean branch, QlBuiltins::BigInt defUB, + QlBuiltins::BigInt guardUB + | phi.isGuardPhi(v, access, guard, branch) and upperBoundFromGuard(guard, access, guardUB, branch) and defUB = getFullyConvertedUpperBounds(access) @@ -1221,10 +1195,10 @@ private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { if guardUB < defUB then result = guardUB else result = defUB ) or - exists(VariableAccess access, float neConstant, float upper | + exists(VariableAccess access, QlBuiltins::BigInt neConstant, QlBuiltins::BigInt upper | isNEPhi(v, phi, access, neConstant) and upper = getTruncatedUpperBounds(access) and - if upper = neConstant then result = upper - 1 else result = upper + if upper = neConstant then result = upper - 1.toBigInt() else result = upper ) or exists(VariableAccess access | @@ -1236,7 +1210,7 @@ private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { } /** Only to be called by `getDefLowerBounds`. */ -private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { +private QlBuiltins::BigInt getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr)) or @@ -1247,18 +1221,18 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { result = getTruncatedLowerBounds(assignOp) ) or - exists(IncrementOperation incr, float newLB | + exists(IncrementOperation incr, QlBuiltins::BigInt newLB | def = incr and incr.getOperand() = v.getAnAccess() and newLB = getFullyConvertedLowerBounds(incr.getOperand()) and - result = newLB + 1 + result = newLB + 1.toBigInt() ) or - exists(DecrementOperation decr, float newLB | + exists(DecrementOperation decr, QlBuiltins::BigInt newLB | def = decr and decr.getOperand() = v.getAnAccess() and newLB = getFullyConvertedLowerBounds(decr.getOperand()) and - result = addRoundingDownSmall(newLB, -1) + result = newLB - 1.toBigInt() ) or // Phi nodes. @@ -1272,7 +1246,7 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { } /** Only to be called by `getDefUpperBounds`. */ -private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { +private QlBuiltins::BigInt getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr)) or @@ -1283,18 +1257,18 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { result = getTruncatedUpperBounds(assignOp) ) or - exists(IncrementOperation incr, float newUB | + exists(IncrementOperation incr, QlBuiltins::BigInt newUB | def = incr and incr.getOperand() = v.getAnAccess() and newUB = getFullyConvertedUpperBounds(incr.getOperand()) and - result = addRoundingUpSmall(newUB, 1) + result = newUB + 1.toBigInt() ) or - exists(DecrementOperation decr, float newUB | + exists(DecrementOperation decr, QlBuiltins::BigInt newUB | def = decr and decr.getOperand() = v.getAnAccess() and newUB = getFullyConvertedUpperBounds(decr.getOperand()) and - result = newUB - 1 + result = newUB - 1.toBigInt() ) or // Phi nodes. @@ -1312,7 +1286,9 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { * unanalyzable definitions (such as function parameters) and make their * bounds unknown. */ -private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v, float lb, float ub) { +private predicate unanalyzableDefBounds( + RangeSsaDefinition def, StackVariable v, QlBuiltins::BigInt lb, QlBuiltins::BigInt ub +) { v = def.getAVariable() and not analyzableDef(def, v) and lb = varMinVal(v) and @@ -1344,8 +1320,10 @@ predicate nonNanGuardedVariable(Expr guard, VariableAccess v, boolean branch) { * predicate uses the bounds information for `r` to compute a lower bound * for `v`. */ -private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, boolean branch) { - exists(float childLB, RelationStrictness strictness | +private predicate lowerBoundFromGuard( + Expr guard, VariableAccess v, QlBuiltins::BigInt lb, boolean branch +) { + exists(QlBuiltins::BigInt childLB, RelationStrictness strictness | boundFromGuard(guard, v, childLB, true, strictness, branch) | if nonNanGuardedVariable(guard, v, branch) @@ -1354,7 +1332,7 @@ private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, bo strictness = Nonstrict() or not getVariableRangeType(v.getTarget()) instanceof IntegralType then lb = childLB - else lb = childLB + 1 + else lb = childLB + 1.toBigInt() else lb = varMinVal(v.getTarget()) ) } @@ -1364,8 +1342,10 @@ private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, bo * predicate uses the bounds information for `r` to compute a upper bound * for `v`. */ -private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, boolean branch) { - exists(float childUB, RelationStrictness strictness | +private predicate upperBoundFromGuard( + Expr guard, VariableAccess v, QlBuiltins::BigInt ub, boolean branch +) { + exists(QlBuiltins::BigInt childUB, RelationStrictness strictness | boundFromGuard(guard, v, childUB, false, strictness, branch) | if nonNanGuardedVariable(guard, v, branch) @@ -1374,7 +1354,7 @@ private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, bo strictness = Nonstrict() or not getVariableRangeType(v.getTarget()) instanceof IntegralType then ub = childUB - else ub = childUB - 1 + else ub = childUB - 1.toBigInt() else ub = varMaxVal(v.getTarget()) ) } @@ -1384,25 +1364,25 @@ private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, bo * `linearBoundFromGuard`. */ private predicate boundFromGuard( - Expr guard, VariableAccess v, float boundValue, boolean isLowerBound, + Expr guard, VariableAccess v, QlBuiltins::BigInt boundValue, boolean isLowerBound, RelationStrictness strictness, boolean branch ) { - exists(float p, float q, float r, boolean isLB | + exists(QlBuiltins::BigInt p, QlBuiltins::BigInt q, QlBuiltins::BigInt r, boolean isLB | linearBoundFromGuard(guard, v, p, q, r, isLB, strictness, branch) and boundValue = (r - q) / p | // If the multiplier is negative then the direction of the comparison // needs to be flipped. - p > 0 and isLowerBound = isLB + p > 0.toBigInt() and isLowerBound = isLB or - p < 0 and isLowerBound = isLB.booleanNot() + p < 0.toBigInt() and isLowerBound = isLB.booleanNot() ) or // When `!e` is true, we know that `0 <= e <= 0` - exists(float p, float q, Expr e | + exists(QlBuiltins::BigInt p, QlBuiltins::BigInt q, Expr e | linearAccess(e, v, p, q) and eqZeroWithNegate(guard, e, true, branch) and - boundValue = (0.0 - q) / p and + boundValue = -q / p and isLowerBound = [false, true] and strictness = Nonstrict() ) @@ -1414,8 +1394,8 @@ private predicate boundFromGuard( * lower or upper bound for `v`. */ private predicate linearBoundFromGuard( - ComparisonOperation guard, VariableAccess v, float p, float q, float boundValue, - boolean isLowerBound, // Is this a lower or an upper bound? + ComparisonOperation guard, VariableAccess v, QlBuiltins::BigInt p, QlBuiltins::BigInt q, + QlBuiltins::BigInt boundValue, boolean isLowerBound, // Is this a lower or an upper bound? RelationStrictness strictness, boolean branch // Which control-flow branch is this bound valid on? ) { // For the comparison x < RHS, we create two bounds: @@ -1451,14 +1431,14 @@ private predicate linearBoundFromGuard( } /** Utility for `linearBoundFromGuard`. */ -private predicate getBounds(Expr expr, float boundValue, boolean isLowerBound) { +private predicate getBounds(Expr expr, QlBuiltins::BigInt boundValue, boolean isLowerBound) { isLowerBound = true and boundValue = getFullyConvertedLowerBounds(expr) or isLowerBound = false and boundValue = getFullyConvertedUpperBounds(expr) } /** Utility for `linearBoundFromGuard`. */ -private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBound) { +private predicate exprTypeBounds(Expr expr, QlBuiltins::BigInt boundValue, boolean isLowerBound) { isLowerBound = true and boundValue = exprMinVal(expr.getFullyConverted()) or isLowerBound = false and boundValue = exprMaxVal(expr.getFullyConverted()) @@ -1470,25 +1450,26 @@ private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBou * Only integral types are supported. */ private predicate isNEPhi( - Variable v, RangeSsaDefinition phi, VariableAccess access, float neConstant + Variable v, RangeSsaDefinition phi, VariableAccess access, QlBuiltins::BigInt neConstant ) { exists( - ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, float r + ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, QlBuiltins::BigInt p, + QlBuiltins::BigInt q, QlBuiltins::BigInt r | phi.isGuardPhi(v, access, cmp, branch) and eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise - r = getValue(rExpr).toFloat() and + r = parseAsBigInt(getValue(rExpr)) and linearAccess(linearExpr, access, p, q) and neConstant = (r - q) / p ) or - exists(Expr op, boolean branch, Expr linearExpr, float p, float q | + exists(Expr op, boolean branch, Expr linearExpr, QlBuiltins::BigInt p, QlBuiltins::BigInt q | phi.isGuardPhi(v, access, op, branch) and eqZeroWithNegate(op, linearExpr, false, branch) and v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise linearAccess(linearExpr, access, p, q) and - neConstant = (0.0 - q) / p + neConstant = -q / p ) } @@ -1514,7 +1495,7 @@ private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, Vari * An upper bound can only be found, if a guard phi node can be found, and the * expression has only one immediate predecessor. */ -private float getGuardedUpperBound(VariableAccess guardedAccess) { +private QlBuiltins::BigInt getGuardedUpperBound(VariableAccess guardedAccess) { exists( RangeSsaDefinition def, StackVariable v, VariableAccess guardVa, Expr guard, boolean branch | @@ -1528,7 +1509,7 @@ private float getGuardedUpperBound(VariableAccess guardedAccess) { // that there is one predecessor, albeit somewhat conservative. exists(unique(BasicBlock b | b = def.(BasicBlock).getAPredecessor())) and guardedAccess = def.getAUse(v) and - result = max(float ub | upperBoundFromGuard(guard, guardVa, ub, branch)) and + result = max(QlBuiltins::BigInt ub | upperBoundFromGuard(guard, guardVa, ub, branch)) and not convertedExprMightOverflow(guard.getAChild+()) ) } @@ -1548,10 +1529,10 @@ private module SimpleRangeAnalysisCached { * `lowerBound(expr.getFullyConverted())` */ cached - float lowerBound(Expr expr) { + QlBuiltins::BigInt lowerBound(Expr expr) { // Combine the lower bounds returned by getTruncatedLowerBounds into a // single minimum value. - result = min(float lb | lb = getTruncatedLowerBounds(expr) | lb) + result = min(QlBuiltins::BigInt lb | lb = getTruncatedLowerBounds(expr) | lb) } /** @@ -1567,7 +1548,7 @@ private module SimpleRangeAnalysisCached { * `upperBound(expr.getFullyConverted())` */ cached - float upperBound(Expr expr) { + QlBuiltins::BigInt upperBound(Expr expr) { // Combine the upper bounds returned by getTruncatedUpperBounds and // getGuardedUpperBound into a single maximum value result = min([max(getTruncatedUpperBounds(expr)), getGuardedUpperBound(expr)]) @@ -1727,14 +1708,14 @@ module SimpleRangeAnalysisInternal { /** * Gets the truncated lower bounds of the fully converted expression. */ - float getFullyConvertedLowerBounds(Expr expr) { + QlBuiltins::BigInt getFullyConvertedLowerBounds(Expr expr) { result = getTruncatedLowerBounds(expr.getFullyConverted()) } /** * Gets the truncated upper bounds of the fully converted expression. */ - float getFullyConvertedUpperBounds(Expr expr) { + QlBuiltins::BigInt getFullyConvertedUpperBounds(Expr expr) { result = getTruncatedUpperBounds(expr.getFullyConverted()) } @@ -1743,8 +1724,8 @@ module SimpleRangeAnalysisInternal { * done by `getDefLowerBoundsImpl`, but this is where widening is applied * to prevent the analysis from exploding due to a recursive definition. */ - float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) { - exists(float newLB, float truncatedLB | + QlBuiltins::BigInt getDefLowerBounds(RangeSsaDefinition def, StackVariable v) { + exists(QlBuiltins::BigInt newLB, QlBuiltins::BigInt truncatedLB | newLB = getDefLowerBoundsImpl(def, v) and if varMinVal(v) <= newLB and newLB <= varMaxVal(v) then truncatedLB = newLB @@ -1758,7 +1739,7 @@ module SimpleRangeAnalysisInternal { // down to one of a limited set of values to prevent the // recursion from exploding. result = - max(float widenLB | + max(QlBuiltins::BigInt widenLB | widenLB = wideningLowerBounds(getVariableRangeType(v)) and not widenLB > truncatedLB | @@ -1773,8 +1754,8 @@ module SimpleRangeAnalysisInternal { } /** See comment for `getDefLowerBounds`, above. */ - float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) { - exists(float newUB, float truncatedUB | + QlBuiltins::BigInt getDefUpperBounds(RangeSsaDefinition def, StackVariable v) { + exists(QlBuiltins::BigInt newUB, QlBuiltins::BigInt truncatedUB | newUB = getDefUpperBoundsImpl(def, v) and if varMinVal(v) <= newUB and newUB <= varMaxVal(v) then truncatedUB = newUB @@ -1788,7 +1769,7 @@ module SimpleRangeAnalysisInternal { // up to one of a fixed set of values to prevent the recursion // from exploding. result = - min(float widenUB | + min(QlBuiltins::BigInt widenUB | widenUB = wideningUpperBounds(getVariableRangeType(v)) and not widenUB < truncatedUB | diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/RangeAnalysisUtil.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/RangeAnalysisUtil.qll index 4fa2ce85e505..9254eaac97ff 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/RangeAnalysisUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/RangeAnalysisUtil.qll @@ -10,7 +10,7 @@ private import semmle.code.cpp.ir.IR pragma[nomagic] private Instruction getABoundIn(SemBound b, IRFunction func) { - getSemanticExpr(result) = b.getExpr(0) and + getSemanticExpr(result) = b.getExpr(0.toBigInt()) and result.getEnclosingIRFunction() = func } @@ -18,7 +18,7 @@ private Instruction getABoundIn(SemBound b, IRFunction func) { * Holds if `i <= b + delta`. */ pragma[inline] -private predicate boundedImplCand(Instruction i, Instruction b, int delta) { +private predicate boundedImplCand(Instruction i, Instruction b, QlBuiltins::BigInt delta) { exists(SemBound bound, IRFunction func | semBounded(getSemanticExpr(i), bound, delta, true, _) and b = getABoundIn(bound, func) and @@ -31,8 +31,8 @@ private predicate boundedImplCand(Instruction i, Instruction b, int delta) { * this condition. */ pragma[inline] -private predicate boundedImpl(Instruction i, Instruction b, int delta) { - delta = min(int cand | boundedImplCand(i, b, cand)) +private predicate boundedImpl(Instruction i, Instruction b, QlBuiltins::BigInt delta) { + delta = min(QlBuiltins::BigInt cand | boundedImplCand(i, b, cand)) } /** @@ -42,7 +42,9 @@ private predicate boundedImpl(Instruction i, Instruction b, int delta) { */ bindingset[i] pragma[inline_late] -predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) } +predicate bounded1(Instruction i, Instruction b, QlBuiltins::BigInt delta) { + boundedImpl(i, b, delta) +} /** * Holds if `i <= b + delta`. @@ -51,7 +53,9 @@ predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, */ bindingset[b] pragma[inline_late] -predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) } +predicate bounded2(Instruction i, Instruction b, QlBuiltins::BigInt delta) { + boundedImpl(i, b, delta) +} /** Holds if `i <= b + delta`. */ predicate bounded = boundedImpl/3; diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/SimpleRangeAnalysis.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/SimpleRangeAnalysis.qll index dc5e1a25f0eb..05d73f706ca2 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/SimpleRangeAnalysis.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/SimpleRangeAnalysis.qll @@ -23,7 +23,7 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils * * `lowerBound(expr.getFullyConverted())` */ -float lowerBound(Expr expr) { +QlBuiltins::BigInt lowerBound(Expr expr) { exists(Instruction i, ConstantBounds::SemBound b | i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound | @@ -43,7 +43,7 @@ float lowerBound(Expr expr) { * * `upperBound(expr.getFullyConverted())` */ -float upperBound(Expr expr) { +QlBuiltins::BigInt upperBound(Expr expr) { exists(Instruction i, ConstantBounds::SemBound b | i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound | @@ -97,7 +97,7 @@ predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) { * due to a conversion. */ predicate exprMightOverflowNegatively(Expr expr) { - lowerBound(expr) < exprMinVal(expr) + lowerBound(expr) < exprMinVal(expr).toString().toBigInt() or exists(SemanticExprConfig::Expr semExpr | semExpr.getAst() = expr and @@ -123,7 +123,7 @@ predicate convertedExprMightOverflowNegatively(Expr expr) { * due to a conversion. */ predicate exprMightOverflowPositively(Expr expr) { - upperBound(expr) > exprMaxVal(expr) + upperBound(expr) > exprMaxVal(expr).toString().toBigInt() or exists(SemanticExprConfig::Expr semExpr | semExpr.getAst() = expr and diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticBound.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticBound.qll index a1814f659fc5..9aaaec6d3207 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticBound.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticBound.qll @@ -17,7 +17,7 @@ class SemBound instanceof Specific::Bound { final SemLocation getLocation() { result = super.getLocation() } - final SemExpr getExpr(int delta) { result = Specific::getBoundExpr(this, delta) } + final SemExpr getExpr(QlBuiltins::BigInt delta) { result = Specific::getBoundExpr(this, delta) } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll index a2905e185f1d..32ac8470f691 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll @@ -85,12 +85,13 @@ class SemIntegerLiteralExpr extends SemNumericLiteralExpr { * If the value is outside the range of an `int`, use `getApproximateFloatValue()` to get a value * that is equal to the actual integer value, within rounding error. */ - final int getIntValue() { Specific::integerLiteral(this, _, result) } + final QlBuiltins::BigInt getIntValue() { Specific::integerLiteral(this, _, result) } final override float getApproximateFloatValue() { - result = this.getIntValue() + result = this.getIntValue().toString().toFloat() or - Specific::largeIntegerLiteral(this, _, result) + Specific::largeIntegerLiteral(this, _, + any(QlBuiltins::BigInt b | result = b.toString().toFloat())) } } diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll index 1b36ae2efc5e..8f001d85a50b 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll @@ -26,18 +26,18 @@ module SemanticExprConfig { ) } - predicate integerLiteral(Expr expr, SemIntegerType type, int value) { + predicate integerLiteral(Expr expr, SemIntegerType type, QlBuiltins::BigInt value) { exists(string valueString | anyConstantExpr(expr, type, valueString) and - value = valueString.toInt() + value = valueString.toBigInt() ) } - predicate largeIntegerLiteral(Expr expr, SemIntegerType type, float approximateFloatValue) { + predicate largeIntegerLiteral(Expr expr, SemIntegerType type, QlBuiltins::BigInt value) { exists(string valueString | anyConstantExpr(expr, type, valueString) and not exists(valueString.toInt()) and - approximateFloatValue = valueString.toFloat() + value = valueString.toBigInt() ) } @@ -229,8 +229,9 @@ module SemanticExprConfig { v.asInstruction() = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction() } - Expr getBoundExpr(Bound bound, int delta) { - result = getSemanticExpr(bound.(IRBound::Bound).getInstruction(delta)) + Expr getBoundExpr(Bound bound, QlBuiltins::BigInt delta) { + result = + getSemanticExpr(bound.(IRBound::Bound).getInstruction(any(int i | i.toBigInt() = delta))) } class Guard = IRGuards::IRGuardCondition; diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysis.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysis.qll index 463817ebfd3f..811aa721d077 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysis.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysis.qll @@ -7,7 +7,7 @@ private import ConstantAnalysisSpecific as Specific /** An expression that always has the same integer value. */ pragma[nomagic] -private predicate constantIntegerExpr(SemExpr e, int val) { +private predicate constantIntegerExpr(SemExpr e, QlBuiltins::BigInt val) { // An integer literal e.(SemIntegerLiteralExpr).getIntValue() = val or @@ -27,5 +27,5 @@ class SemConstantIntegerExpr extends SemExpr { SemConstantIntegerExpr() { constantIntegerExpr(this, _) } /** Gets the integer value of this expression. */ - int getIntValue() { constantIntegerExpr(this, result) } + QlBuiltins::BigInt getIntValue() { constantIntegerExpr(this, result) } } diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysisSpecific.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysisSpecific.qll index 4713a10ebfcc..5aa79c52ab8d 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysisSpecific.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/ConstantAnalysisSpecific.qll @@ -7,4 +7,4 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic /** * Gets the constant integer value of the specified expression, if any. */ -int getIntConstantValue(SemExpr expr) { none() } +QlBuiltins::BigInt getIntConstantValue(SemExpr expr) { none() } diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/FloatDelta.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/FloatDelta.qll index 2cdeb9544ab7..b1d513c0574d 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/FloatDelta.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/FloatDelta.qll @@ -3,35 +3,16 @@ private import codeql.rangeanalysis.RangeAnalysis private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType -module FloatDelta implements DeltaSig { - class Delta = float; - - bindingset[d] - bindingset[result] - float toFloat(Delta d) { result = d } - - bindingset[d] - bindingset[result] - int toInt(Delta d) { result = d } - - bindingset[n] - bindingset[result] - Delta fromInt(int n) { result = n } - - bindingset[f] - Delta fromFloat(float f) { result = f } -} - -module FloatOverflow implements OverflowSig { +module FloatOverflow implements OverflowSig { predicate semExprDoesNotOverflow(boolean positively, SemExpr expr) { - exists(float lb, float ub, float delta | + exists(float lb, float ub, QlBuiltins::BigInt delta | typeBounds(expr.getSemType(), lb, ub) and ConstantStage::initialBounded(expr, any(ConstantBounds::SemZeroBound b), delta, positively, _, _, _) | - positively = true and delta < ub + positively = true and delta < ub.toString().toBigInt() or - positively = false and delta > lb + positively = false and delta > lb.toString().toBigInt() ) } diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll index e9a7dc836e43..d75deac7f5f9 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll @@ -3,11 +3,10 @@ */ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic -private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta private import RangeAnalysisImpl private import codeql.rangeanalysis.RangeAnalysis -module CppLangImplConstant implements LangSig { +module CppLangImplConstant implements LangSig { /** * Ignore the bound on this expression. * @@ -19,12 +18,14 @@ module CppLangImplConstant implements LangSig { /** * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`). */ - predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() } + predicate hasConstantBound(SemExpr e, QlBuiltins::BigInt bound, boolean upper) { none() } /** * Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`). */ - predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() } + predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, QlBuiltins::BigInt delta, boolean upper) { + none() + } predicate includeConstantBounds() { any() } diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisImpl.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisImpl.qll index a19baf2eea78..0d300dd053a6 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisImpl.qll @@ -1,6 +1,5 @@ private import RangeAnalysisConstantSpecific private import RangeAnalysisRelativeSpecific -private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard @@ -11,6 +10,7 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType private import SemanticType private import codeql.rangeanalysis.RangeAnalysis private import ConstantAnalysis as ConstantAnalysis +private import FloatDelta module Sem implements Semantic { class Expr = SemExpr; @@ -97,7 +97,7 @@ module Sem implements Semantic { class SsaExplicitUpdate = SemSsaExplicitUpdate; - predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() } + predicate additionalValueFlowStep(SemExpr dest, SemExpr src, QlBuiltins::BigInt delta) { none() } predicate conversionCannotOverflow(Type fromType, Type toType) { SemanticType::conversionCannotOverflow(fromType, toType) @@ -106,10 +106,10 @@ module Sem implements Semantic { module SignAnalysis implements SignAnalysisSig { private import SignAnalysisCommon as SA - import SA::SignAnalysis + import SA::SignAnalysis } -module ConstantBounds implements BoundSig { +module ConstantBounds implements BoundSig { class SemBound instanceof SemanticBound::SemBound { SemBound() { this instanceof SemanticBound::SemZeroBound @@ -121,7 +121,7 @@ module ConstantBounds implements BoundSig { SemLocation getLocation() { result = super.getLocation() } - SemExpr getExpr(float delta) { result = super.getExpr(delta) } + SemExpr getExpr(QlBuiltins::BigInt delta) { result = super.getExpr(delta) } } class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { } @@ -131,7 +131,7 @@ module ConstantBounds implements BoundSig { } } -module RelativeBounds implements BoundSig { +module RelativeBounds implements BoundSig { class SemBound instanceof SemanticBound::SemBound { SemBound() { not this instanceof SemanticBound::SemZeroBound } @@ -139,7 +139,7 @@ module RelativeBounds implements BoundSig { SemLocation getLocation() { result = super.getLocation() } - SemExpr getExpr(float delta) { result = super.getExpr(delta) } + SemExpr getExpr(QlBuiltins::BigInt delta) { result = super.getExpr(delta) } } class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { } @@ -149,13 +149,13 @@ module RelativeBounds implements BoundSig { } } -module AllBounds implements BoundSig { +module AllBounds implements BoundSig { class SemBound instanceof SemanticBound::SemBound { string toString() { result = super.toString() } SemLocation getLocation() { result = super.getLocation() } - SemExpr getExpr(float delta) { result = super.getExpr(delta) } + SemExpr getExpr(QlBuiltins::BigInt delta) { result = super.getExpr(delta) } } class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { } @@ -169,16 +169,16 @@ private module ModulusAnalysisInstantiated implements ModulusAnalysisSig { class ModBound = AllBounds::SemBound; private import codeql.rangeanalysis.ModulusAnalysis as MA - import MA::ModulusAnalysis + import MA::ModulusAnalysis } module ConstantStage = - RangeStage; + RangeStage; module RelativeStage = - RangeStage; + RangeStage; private newtype TSemReason = TSemNoReason() or @@ -204,7 +204,7 @@ import Public module Public { predicate semBounded( - SemExpr e, SemanticBound::SemBound b, float delta, boolean upper, SemReason reason + SemExpr e, SemanticBound::SemBound b, QlBuiltins::BigInt delta, boolean upper, SemReason reason ) { ConstantStage::semBounded(e, b, delta, upper, constantReason(reason)) or diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll index 3774d47db8b2..85424ece40b2 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll @@ -3,12 +3,11 @@ */ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic -private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta private import RangeAnalysisImpl private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils private import codeql.rangeanalysis.RangeAnalysis -module CppLangImplRelative implements LangSig { +module CppLangImplRelative implements LangSig { /** * Ignore the bound on this expression. * @@ -16,15 +15,17 @@ module CppLangImplRelative implements LangSig { * removed once we have the new implementation matching the old results exactly. */ predicate ignoreExprBound(SemExpr e) { - exists(boolean upper, float delta, ConstantBounds::SemZeroBound b, float lb, float ub | + exists( + boolean upper, QlBuiltins::BigInt delta, ConstantBounds::SemZeroBound b, float lb, float ub + | ConstantStage::semBounded(e, b, delta, upper, _) and typeBounds(e.getSemType(), lb, ub) and ( upper = false and - delta < lb + delta < lb.toString().toBigInt() or upper = true and - delta > ub + delta > ub.toString().toBigInt() ) ) } @@ -51,12 +52,14 @@ module CppLangImplRelative implements LangSig { /** * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`). */ - predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() } + predicate hasConstantBound(SemExpr e, QlBuiltins::BigInt bound, boolean upper) { none() } /** * Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`). */ - predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() } + predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, QlBuiltins::BigInt delta, boolean upper) { + none() + } predicate includeConstantBounds() { none() } diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/SignAnalysisCommon.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/SignAnalysisCommon.qll index 9cd57e5ed622..6215247648cb 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/SignAnalysisCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/SignAnalysisCommon.qll @@ -13,8 +13,8 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic private import ConstantAnalysis private import Sign -module SignAnalysis { - private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils +module SignAnalysis { + private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils /** * An SSA definition for which the analysis can compute the sign. @@ -100,12 +100,12 @@ module SignAnalysis { } final override Sign getSign() { - exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i | - i < 0 and result = TNeg() + exists(QlBuiltins::BigInt i | this.(SemConstantIntegerExpr).getIntValue() = i | + i < 0.toBigInt() and result = TNeg() or - i = 0 and result = TZero() + i = 0.toBigInt() and result = TZero() or - i > 0 and result = TPos() + i > 0.toBigInt() and result = TPos() ) or not exists(this.(SemConstantIntegerExpr).getIntValue()) and @@ -298,12 +298,12 @@ module SignAnalysis { | testIsTrue = true and comp.getLesserOperand() = lowerbound and - comp.getGreaterOperand() = ssaRead(v, D::fromInt(0)) and + comp.getGreaterOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = true else isStrict = false) or testIsTrue = false and comp.getGreaterOperand() = lowerbound and - comp.getLesserOperand() = ssaRead(v, D::fromInt(0)) and + comp.getLesserOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = false else isStrict = true) ) } @@ -322,12 +322,12 @@ module SignAnalysis { | testIsTrue = true and comp.getGreaterOperand() = upperbound and - comp.getLesserOperand() = ssaRead(v, D::fromInt(0)) and + comp.getLesserOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = true else isStrict = false) or testIsTrue = false and comp.getLesserOperand() = upperbound and - comp.getGreaterOperand() = ssaRead(v, D::fromInt(0)) and + comp.getGreaterOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = false else isStrict = true) ) } @@ -343,7 +343,7 @@ module SignAnalysis { exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e | pos.hasReadOfVar(pragma[only_bind_into](v)) and guardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and - e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and + e = ssaRead(pragma[only_bind_into](v), 0.toBigInt()) and guard.isEquality(eqbound, e, polarity) and isEq = polarity.booleanXor(testIsTrue).booleanNot() and not unknownSign(eqbound) diff --git a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/AllocationToInvalidPointer.qll b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/AllocationToInvalidPointer.qll index 83017aec3537..f1b49988f28c 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/AllocationToInvalidPointer.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/AllocationToInvalidPointer.qll @@ -77,8 +77,8 @@ private Expr getASizeCandidate(Expr size) { * Holds if the `(n, state)` pair represents the source of flow for the size * expression associated with `alloc`. */ -predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) { - exists(VariableAccess va, Expr size, int delta, Expr s | +predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, QlBuiltins::BigInt state) { + exists(VariableAccess va, Expr size, QlBuiltins::BigInt delta, Expr s | size = alloc.getSizeExpr() and s = getASizeCandidate(size) and // Get the unique variable in a size expression like `x` in `malloc(x + 1)`. @@ -146,7 +146,7 @@ private module SizeBarrier { module SizeBarrierFlow = DataFlow::Global; - private int getASizeAddend(DataFlow::Node node) { + private QlBuiltins::BigInt getASizeAddend(DataFlow::Node node) { exists(DataFlow::Node source | SizeBarrierFlow::flow(source, node) and hasSize(_, source, result) @@ -168,7 +168,7 @@ private module SizeBarrier { * `small <= _ + k` and `small` is the "small side" of of a relational comparison that checks * whether `small <= size` where `size` is the size of an allocation. */ - Instruction getABarrierInstruction0(int delta, int k) { + Instruction getABarrierInstruction0(QlBuiltins::BigInt delta, int k) { exists( IRGuardCondition g, ValueNumber value, Operand small, boolean edge, DataFlow::Node large | @@ -183,7 +183,7 @@ private module SizeBarrier { pragma[only_bind_into](k), pragma[only_bind_into](edge)) and bounded(result, value.getAnInstruction(), delta) and g.controls(result.getBlock(), edge) and - k < getASizeAddend(large) + k.toBigInt() < getASizeAddend(large) ) } @@ -193,9 +193,9 @@ private module SizeBarrier { */ bindingset[state] pragma[inline_late] - Instruction getABarrierInstruction(int state) { - exists(int delta, int k | - state > k + delta and + Instruction getABarrierInstruction(QlBuiltins::BigInt state) { + exists(QlBuiltins::BigInt delta, int k | + state > k.toBigInt() + delta and // result <= "size of allocation" + delta + k // < "size of allocation" + state result = getABarrierInstruction0(delta, k) @@ -206,12 +206,12 @@ private module SizeBarrier { * Gets a `DataFlow::Node` that is guarded by a guard condition which ensures that * the value of the node is upper-bounded by size of some allocation. */ - DataFlow::Node getABarrierNode(int state) { - exists(DataFlow::Node source, int delta, int k | + DataFlow::Node getABarrierNode(QlBuiltins::BigInt state) { + exists(DataFlow::Node source, QlBuiltins::BigInt delta, int k | SizeBarrierFlow::flow(source, result) and hasSize(_, source, state) and result.asInstruction() = SizeBarrier::getABarrierInstruction0(delta, k) and - state > k + delta + state > k.toBigInt() + delta // so now we have: // result <= "size of allocation" + delta + k // < "size of allocation" + state @@ -270,7 +270,7 @@ private module InterestingPointerAddInstruction { private module Config implements ProductFlow::StateConfigSig { class FlowState1 = Unit; - class FlowState2 = int; + class FlowState2 = QlBuiltins::BigInt; predicate isSourcePair( DataFlow::Node allocSource, FlowState1 unit, DataFlow::Node sizeSource, FlowState2 sizeAddend @@ -350,7 +350,8 @@ private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState; */ pragma[nomagic] private predicate pointerAddInstructionHasBounds0( - PointerAddInstruction pai, DataFlow::Node allocSink, DataFlow::Node sizeSink, int delta + PointerAddInstruction pai, DataFlow::Node allocSink, DataFlow::Node sizeSink, + QlBuiltins::BigInt delta ) { InterestingPointerAddInstruction::isInteresting(pragma[only_bind_into](pai)) and exists(Instruction right, Instruction sizeInstr | @@ -371,7 +372,8 @@ private predicate pointerAddInstructionHasBounds0( */ pragma[nomagic] predicate pointerAddInstructionHasBounds( - DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node allocSink, int delta + DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node allocSink, + QlBuiltins::BigInt delta ) { exists(DataFlow::Node sizeSink | AllocToInvalidPointerFlow::flow(allocation, _, allocSink, sizeSink) and diff --git a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll index 90d7f04f7ca7..91a72df1a034 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll @@ -95,7 +95,7 @@ private module InvalidPointerToDerefBarrier { additional predicate isSource(DataFlow::Node source, PointerArithmeticInstruction pai) { invalidPointerToDerefSource(_, pai, _) and // source <= pai - bounded2(source.asInstruction(), pai, any(int d | d <= 0)) + bounded2(source.asInstruction(), pai, any(QlBuiltins::BigInt d | d <= 0.toBigInt())) } predicate isSource(DataFlow::Node source) { isSource(source, _) } @@ -135,7 +135,10 @@ private module InvalidPointerToDerefBarrier { * Gets an instruction `instr` such that `instr < pai`. */ Instruction getABarrierInstruction(PointerArithmeticInstruction pai) { - exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge, int delta, int k | + exists( + IRGuardCondition g, ValueNumber value, Operand use, boolean edge, QlBuiltins::BigInt delta, + int k + | use = value.getAUse() and // value < pai + k operandGuardChecks(pai, pragma[only_bind_into](g), pragma[only_bind_into](use), @@ -143,7 +146,7 @@ private module InvalidPointerToDerefBarrier { // result <= value + delta bounded(result, value.getAnInstruction(), delta) and g.controls(result.getBlock(), edge) and - delta + k <= 0 + delta + k.toBigInt() <= 0.toBigInt() // combining the above we have: result < pai + k + delta <= pai ) } @@ -216,12 +219,12 @@ private predicate invalidPointerToDerefSource( pragma[inline] private predicate isInvalidPointerDerefSink( DataFlow::Node sink, AddressOperand addr, Instruction i, string operation, - int deltaDerefSinkAndDerefAddress + QlBuiltins::BigInt deltaDerefSinkAndDerefAddress ) { exists(Instruction s | s = sink.asInstruction() and bounded(addr.getDef(), s, deltaDerefSinkAndDerefAddress) and - deltaDerefSinkAndDerefAddress >= 0 and + deltaDerefSinkAndDerefAddress >= 0.toBigInt() and i.getAnOperand() = addr | i instanceof StoreInstruction and @@ -262,7 +265,7 @@ private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFl */ private predicate derefSinkToOperation( DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation, - string description, int deltaDerefSinkAndDerefAddress + string description, QlBuiltins::BigInt deltaDerefSinkAndDerefAddress ) { exists(Instruction operationInstr, AddressOperand addr | paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and @@ -284,7 +287,7 @@ private predicate derefSinkToOperation( */ predicate operationIsOffBy( DataFlow::Node allocation, PointerArithmeticInstruction pai, DataFlow::Node derefSource, - DataFlow::Node derefSink, string description, DataFlow::Node operation, int delta + DataFlow::Node derefSink, string description, DataFlow::Node operation, QlBuiltins::BigInt delta ) { invalidPointerToDerefSource(allocation, pai, derefSource) and flow(derefSource, derefSink) and diff --git a/cpp/ql/src/Critical/OverflowStatic.ql b/cpp/ql/src/Critical/OverflowStatic.ql index 13a4fb6bcb76..f11ebdd77b15 100644 --- a/cpp/ql/src/Critical/OverflowStatic.ql +++ b/cpp/ql/src/Critical/OverflowStatic.ql @@ -56,7 +56,8 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) { loop.limit() >= bufaccess.bufferSize() and loop.counter().getAnAccess() = bufaccess.getArrayOffset() and // Ensure that we don't have an upper bound on the array index that's less than the buffer size. - not upperBound(bufaccess.getArrayOffset().getFullyConverted()) < bufaccess.bufferSize() and + not upperBound(bufaccess.getArrayOffset().getFullyConverted()) < + bufaccess.bufferSize().toBigInt() and // The upper bounds analysis must not have been widended not upperBoundMayBeWidened(bufaccess.getArrayOffset().getFullyConverted()) and msg = @@ -101,7 +102,7 @@ class CallWithBufferSize extends FunctionCall { ) } - int statedSizeValue() { + QlBuiltins::BigInt statedSizeValue() { // `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful // result in this case we pick the minimum value obtainable from dataflow and range analysis. result = @@ -109,16 +110,16 @@ class CallWithBufferSize extends FunctionCall { .minimum(min(Expr statedSizeSrc | DataFlow::localExprFlow(statedSizeSrc, this.statedSizeExpr()) | - statedSizeSrc.getValue().toInt() + statedSizeSrc.getValue().toBigInt() )) } } predicate wrongBufferSize(Expr error, string msg) { - exists(CallWithBufferSize call, int bufsize, Variable buf, int statedSize | + exists(CallWithBufferSize call, int bufsize, Variable buf, QlBuiltins::BigInt statedSize | staticBuffer(call.buffer(), buf, bufsize) and statedSize = call.statedSizeValue() and - statedSize > bufsize and + statedSize > bufsize.toBigInt() and error = call.statedSizeExpr() and msg = "Potential buffer-overflow: '" + buf.getName() + "' has size " + bufsize.toString() + " not " + diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql index ba7a6b58aa01..29cd160cad4f 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql +++ b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql @@ -76,20 +76,22 @@ int getEffectiveMulOperands(MulExpr me) { * using SimpleRangeAnalysis. */ class AnalyzableExpr extends Expr { - float maxValue() { result = upperBound(this.getFullyConverted()) } + QlBuiltins::BigInt maxValue() { result = upperBound(this.getFullyConverted()) } - float minValue() { result = lowerBound(this.getFullyConverted()) } + QlBuiltins::BigInt minValue() { result = lowerBound(this.getFullyConverted()) } } class ParenAnalyzableExpr extends AnalyzableExpr, ParenthesisExpr { - override float maxValue() { result = this.getExpr().(AnalyzableExpr).maxValue() } + override QlBuiltins::BigInt maxValue() { result = this.getExpr().(AnalyzableExpr).maxValue() } - override float minValue() { result = this.getExpr().(AnalyzableExpr).minValue() } + override QlBuiltins::BigInt minValue() { result = this.getExpr().(AnalyzableExpr).minValue() } } class MulAnalyzableExpr extends AnalyzableExpr, MulExpr { - override float maxValue() { - exists(float x1, float y1, float x2, float y2 | + override QlBuiltins::BigInt maxValue() { + exists( + QlBuiltins::BigInt x1, QlBuiltins::BigInt y1, QlBuiltins::BigInt x2, QlBuiltins::BigInt y2 + | x1 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() and x2 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() and y1 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() and @@ -98,8 +100,10 @@ class MulAnalyzableExpr extends AnalyzableExpr, MulExpr { ) } - override float minValue() { - exists(float x1, float x2, float y1, float y2 | + override QlBuiltins::BigInt minValue() { + exists( + QlBuiltins::BigInt x1, QlBuiltins::BigInt x2, QlBuiltins::BigInt y1, QlBuiltins::BigInt y2 + | x1 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() and x2 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() and y1 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() and @@ -110,13 +114,13 @@ class MulAnalyzableExpr extends AnalyzableExpr, MulExpr { } class AddAnalyzableExpr extends AnalyzableExpr, AddExpr { - override float maxValue() { + override QlBuiltins::BigInt maxValue() { result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() + this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue() } - override float minValue() { + override QlBuiltins::BigInt minValue() { result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() + this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() @@ -124,13 +128,13 @@ class AddAnalyzableExpr extends AnalyzableExpr, AddExpr { } class SubAnalyzableExpr extends AnalyzableExpr, SubExpr { - override float maxValue() { + override QlBuiltins::BigInt maxValue() { result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() - this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() } - override float minValue() { + override QlBuiltins::BigInt minValue() { result = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() - this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue() @@ -140,7 +144,7 @@ class SubAnalyzableExpr extends AnalyzableExpr, SubExpr { class VarAnalyzableExpr extends AnalyzableExpr, VariableAccess { VarAnalyzableExpr() { this.getTarget() instanceof StackVariable } - override float maxValue() { + override QlBuiltins::BigInt maxValue() { exists(SsaDefinition def, Variable v | def.getAUse(v) = this and // if there is a defining expression, use that for @@ -152,7 +156,7 @@ class VarAnalyzableExpr extends AnalyzableExpr, VariableAccess { ) } - override float minValue() { + override QlBuiltins::BigInt minValue() { exists(SsaDefinition def, Variable v | def.getAUse(v) = this and if exists(def.getDefiningValue(v)) diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/PointlessComparison.ql b/cpp/ql/src/Likely Bugs/Arithmetic/PointlessComparison.ql index e2fe02be867f..991fc258d30b 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/PointlessComparison.ql +++ b/cpp/ql/src/Likely Bugs/Arithmetic/PointlessComparison.ql @@ -26,7 +26,9 @@ import UnsignedGEZero // So to reduce the number of false positives, we do not report a result if // the comparison is in a macro expansion. Similarly for template // instantiations. -from ComparisonOperation cmp, SmallSide ss, float left, float right, boolean value, string reason +from + ComparisonOperation cmp, SmallSide ss, QlBuiltins::BigInt left, QlBuiltins::BigInt right, + boolean value, string reason where not cmp.isInMacroExpansion() and not cmp.isFromTemplateInstantiation(_) and diff --git a/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql b/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql index 1872234ead20..b6172666e2b3 100644 --- a/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql +++ b/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql @@ -30,8 +30,8 @@ VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result } * Holds if `(n, state)` pair represents the source of flow for the size * expression associated with `alloc`. */ -predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) { - exists(VariableAccess va, Expr size, int delta | +predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, QlBuiltins::BigInt state) { + exists(VariableAccess va, Expr size, QlBuiltins::BigInt delta | size = alloc.getSizeExpr() and // Get the unique variable in a size expression like `x` in `malloc(x + 1)`. va = unique( | | getAVariableAccess(size)) and @@ -44,7 +44,8 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) { } predicate isSinkPairImpl( - CallInstruction c, DataFlow::Node bufSink, DataFlow::Node sizeSink, int delta, Expr eBuf + CallInstruction c, DataFlow::Node bufSink, DataFlow::Node sizeSink, QlBuiltins::BigInt delta, + Expr eBuf ) { exists( int bufIndex, int sizeIndex, Instruction sizeInstr, Instruction bufInstr, ArrayFunction func @@ -109,9 +110,9 @@ module ValidState { * while(unknown()) { size++; } * ``` */ - private predicate validStateImpl(PathNode n, int value) { + private predicate validStateImpl(PathNode n, QlBuiltins::BigInt value) { // If the dataflow node depends recursively on itself we restrict the range. - (inLoop(n) implies value = [-2 .. 2]) and + (inLoop(n) implies value = ([-2 .. 2]).toBigInt()) and ( // For the dataflow source we have an allocation such as `malloc(size + k)`, // and the value of the flow-state is then `k`. @@ -129,7 +130,7 @@ module ValidState { // // So we find a valid flow-state at the sink's predecessor, and use the definition // of our sink predicate to compute the valid flow-states at the sink. - exists(int delta, PathNode n0 | + exists(QlBuiltins::BigInt delta, PathNode n0 | n0.getASuccessor() = n and validStateImpl(n0, value) and isSinkPairImpl(_, _, n.getNode(), delta, _) and @@ -144,13 +145,13 @@ module ValidState { // `AddInstruction` to the flow-state of any predecessor node. // For case 2 we simply propagate the valid flow-states from the predecessor node to // the next one. - exists(PathNode n0, DataFlow::Node node0, DataFlow::Node node, int value0 | + exists(PathNode n0, DataFlow::Node node0, DataFlow::Node node, QlBuiltins::BigInt value0 | n0.getASuccessor() = n and validStateImpl(n0, value0) and node = n.getNode() and node0 = n0.getNode() | - exists(int delta | + exists(QlBuiltins::BigInt delta | isAdditionalFlowStep2(node0, node, delta) and value0 = value + delta ) @@ -161,7 +162,7 @@ module ValidState { ) } - predicate validState(DataFlow::Node n, int value) { + predicate validState(DataFlow::Node n, QlBuiltins::BigInt value) { validStateImpl(any(PathNode pn | pn.getNode() = n), value) } } @@ -174,7 +175,7 @@ import ValidState * 1. `node1` is the dataflow node that represents `op1`, and * 2. the value of `op2` can be upper bounded by `delta.` */ -predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2, int delta) { +predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2, QlBuiltins::BigInt delta) { exists(AddInstruction add, Operand op | add.hasOperands(node1.asOperand(), op) and semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and @@ -185,7 +186,7 @@ predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2, int module StringSizeConfig implements ProductFlow::StateConfigSig { class FlowState1 = Unit; - class FlowState2 = int; + class FlowState2 = QlBuiltins::BigInt; predicate isSourcePair( DataFlow::Node bufSource, FlowState1 state1, DataFlow::Node sizeSource, FlowState2 state2 @@ -206,7 +207,7 @@ module StringSizeConfig implements ProductFlow::StateConfigSig { ) { exists(state1) and validState(sizeSink, state2) and - exists(int delta | + exists(QlBuiltins::BigInt delta | isSinkPairImpl(_, bufSink, sizeSink, delta, _) and delta > state2 ) @@ -220,7 +221,7 @@ module StringSizeConfig implements ProductFlow::StateConfigSig { DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2 ) { validState(node2, state2) and - exists(int delta | + exists(QlBuiltins::BigInt delta | isAdditionalFlowStep2(node1, node2, delta) and state1 = state2 + delta ) @@ -239,11 +240,11 @@ module StringSizeFlow = ProductFlow::GlobalWithState; * the columns down to the underlying `DataFlow::Node` in order to deduplicate the flow * state. */ -int getOverflow( +QlBuiltins::BigInt getOverflow( DataFlow::Node source1, DataFlow::Node source2, DataFlow::Node sink1, DataFlow::Node sink2, CallInstruction c, Expr buffer ) { - result > 0 and + result > 0.toBigInt() and exists( StringSizeFlow::PathNode1 pathSource1, StringSizeFlow::PathNode2 pathSource2, StringSizeFlow::PathNode1 pathSink1, StringSizeFlow::PathNode2 pathSink2 @@ -259,14 +260,14 @@ int getOverflow( from StringSizeFlow::PathNode1 source1, StringSizeFlow::PathNode2 source2, - StringSizeFlow::PathNode1 sink1, StringSizeFlow::PathNode2 sink2, int overflow, CallInstruction c, - Expr buffer, string element + StringSizeFlow::PathNode1 sink1, StringSizeFlow::PathNode2 sink2, QlBuiltins::BigInt overflow, + CallInstruction c, Expr buffer, string element where StringSizeFlow::flowPath(source1, source2, sink1, sink2) and overflow = max(getOverflow(source1.getNode(), source2.getNode(), sink1.getNode(), sink2.getNode(), c, buffer) ) and - if overflow = 1 then element = " element." else element = " elements." + if overflow = 1.toBigInt() then element = " element." else element = " elements." select c.getUnconvertedResultExpression(), source1, sink1, "This write may overflow $@ by " + overflow + element, buffer, buffer.toString() diff --git a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql index 7d9ef88adea1..a6402d7791e9 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql @@ -58,7 +58,8 @@ where // We adjust the comparison size in the case of a signed integer type. // This is to exclude the sign bit from the comparison that determines if the small type's size is sufficient to hold // the value of the larger type determined with range analysis. - upperBound(conv).log2() > (getComparisonSize(small) * 8 - getComparisonSizeAdjustment(small)) + upperBound(conv).toString().length() / 10.log() > + (getComparisonSize(small) * 8 - getComparisonSizeAdjustment(small)) ) and // Ignore cases where the smaller type is int or larger // These are still bugs, but you should need a very large string or array to diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql index 5f7d88e9a716..973523b6fcd5 100644 --- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql +++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql @@ -57,20 +57,20 @@ predicate exprIsSubLeftOrLess(SubExpr sub, DataFlow::Node n) { isGuarded(sub, other.asExpr(), n.asExpr()) // other >= n ) or - exists(DataFlow::Node other, float p, float q | + exists(DataFlow::Node other, QlBuiltins::BigInt p, QlBuiltins::BigInt q | // linear access of `other` exprIsSubLeftOrLess(sub, other) and linearAccess(n.asExpr(), other.asExpr(), p, q) and // n = p * other + q - p <= 1 and - q <= 0 + p <= 1.toBigInt() and + q <= 0.toBigInt() ) or - exists(DataFlow::Node other, float p, float q | + exists(DataFlow::Node other, QlBuiltins::BigInt p, QlBuiltins::BigInt q | // linear access of `n` exprIsSubLeftOrLess(sub, other) and linearAccess(other.asExpr(), n.asExpr(), p, q) and // other = p * n + q - p >= 1 and - q >= 0 + p >= 1.toBigInt() and + q >= 0.toBigInt() ) ) } diff --git a/cpp/ql/src/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/Security/CWE/CWE-193/InvalidPointerDeref.ql index d53266424026..ddb608c3b0b6 100644 --- a/cpp/ql/src/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -137,7 +137,7 @@ module FinalFlow = DataFlow::GlobalWithState; */ predicate hasFlowPath( FinalFlow::PathNode source, FinalFlow::PathNode sink, PointerArithmeticInstruction pai, - string operation, int delta + string operation, QlBuiltins::BigInt delta ) { FinalFlow::flowPath(source, sink) and operationIsOffBy(source.getNode(), pai, _, _, operation, sink.getNode(), delta) and @@ -145,13 +145,13 @@ predicate hasFlowPath( } from - FinalFlow::PathNode source, FinalFlow::PathNode sink, int k, string kstr, + FinalFlow::PathNode source, FinalFlow::PathNode sink, QlBuiltins::BigInt k, string kstr, PointerArithmeticInstruction pai, string operation, Expr offset, DataFlow::Node n where - k = min(int cand | hasFlowPath(source, sink, pai, operation, cand)) and + k = min(QlBuiltins::BigInt cand | hasFlowPath(source, sink, pai, operation, cand)) and offset = pai.getRight().getUnconvertedResultExpression() and n = source.getNode() and - if k = 0 then kstr = "" else kstr = " + " + k + if k = 0.toBigInt() then kstr = "" else kstr = " + " + k select sink.getNode(), source, sink, "This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr + ".", n, n.toString(), offset, offset.toString() diff --git a/cpp/ql/src/experimental/Likely Bugs/ArrayAccessProductFlow.ql b/cpp/ql/src/experimental/Likely Bugs/ArrayAccessProductFlow.ql index ffb9362417e1..549b5621fd0d 100644 --- a/cpp/ql/src/experimental/Likely Bugs/ArrayAccessProductFlow.ql +++ b/cpp/ql/src/experimental/Likely Bugs/ArrayAccessProductFlow.ql @@ -34,7 +34,7 @@ class PhpEmalloc extends AllocationFunction { override int getSizeArg() { result = 0 } } -predicate bounded(Instruction i, Bound b, int delta, boolean upper) { +predicate bounded(Instruction i, Bound b, QlBuiltins::BigInt delta, boolean upper) { // TODO: reason semBounded(getSemanticExpr(i), b, delta, upper, _) } @@ -45,17 +45,17 @@ module ArraySizeConfig implements ProductFlow::ConfigSig { } predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) { - exists(PointerAddInstruction pai, int delta | + exists(PointerAddInstruction pai, QlBuiltins::BigInt delta | isSinkPair1(sink1, sink2, pai, delta) and ( - delta = 0 and + delta = 0.toBigInt() and exists(DataFlow::Node paiNode, DataFlow::Node derefNode | DataFlow::localFlow(paiNode, derefNode) and paiNode.asInstruction() = pai and derefNode.asOperand() instanceof AddressOperand ) or - delta >= 1 + delta >= 1.toBigInt() ) ) } @@ -65,7 +65,7 @@ module ArraySizeFlow = ProductFlow::Global; pragma[nomagic] predicate isSinkPair1( - DataFlow::Node sink1, DataFlow::Node sink2, PointerAddInstruction pai, int delta + DataFlow::Node sink1, DataFlow::Node sink2, PointerAddInstruction pai, QlBuiltins::BigInt delta ) { exists(Instruction index, ValueNumberBound b | pai.getRight() = index and diff --git a/cpp/ql/src/experimental/Likely Bugs/DerefNullResult.cpp b/cpp/ql/src/experimental/Likely Bugs/DerefNullResult.cpp index f96d67517b75..787019bb3abf 100644 --- a/cpp/ql/src/experimental/Likely Bugs/DerefNullResult.cpp +++ b/cpp/ql/src/experimental/Likely Bugs/DerefNullResult.cpp @@ -1,3 +1,8 @@ +#define NULL nullptr +char *malloc(int); +void printf(const char *, ...); +int snprintf(char *, int, const char *); + char * create (int arg) { if (arg > 42) { // this function may return NULL diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp index 3765d0b14d40..7b9aa815d464 100644 --- a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp @@ -1,3 +1,5 @@ +#define NULL nullptr + void test(char *arg1, int *arg2) { if (arg1[0] == 'A') { if (arg2 != NULL) { //maybe redundant diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.expected b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.expected new file mode 100644 index 000000000000..9b7a14eedf05 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.expected @@ -0,0 +1,8 @@ +edges +| ConstantSizeArrayOffByOne.cpp:11:9:11:11 | buf | ConstantSizeArrayOffByOne.cpp:11:5:11:14 | access to array | provenance | Config | +nodes +| ConstantSizeArrayOffByOne.cpp:11:5:11:14 | access to array | semmle.label | access to array | +| ConstantSizeArrayOffByOne.cpp:11:9:11:11 | buf | semmle.label | buf | +subpaths +#select +| ConstantSizeArrayOffByOne.cpp:11:5:11:14 | PointerAdd: access to array | ConstantSizeArrayOffByOne.cpp:11:9:11:11 | buf | ConstantSizeArrayOffByOne.cpp:11:5:11:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | ConstantSizeArrayOffByOne.cpp:4:7:4:9 | buf | buf | ConstantSizeArrayOffByOne.cpp:11:5:11:18 | Store: ... = ... | write | diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index c38a012b27bf..3f5fa1ee9864 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -18,7 +18,7 @@ import ArrayAddressToDerefFlow::PathGraph pragma[nomagic] Instruction getABoundIn(SemBound b, IRFunction func) { - getSemanticExpr(result) = b.getExpr(0) and + getSemanticExpr(result) = b.getExpr(0.toBigInt()) and result.getEnclosingIRFunction() = func } @@ -26,7 +26,7 @@ Instruction getABoundIn(SemBound b, IRFunction func) { * Holds if `i <= b + delta`. */ pragma[inline] -predicate boundedImpl(Instruction i, Instruction b, int delta) { +predicate boundedImpl(Instruction i, Instruction b, QlBuiltins::BigInt delta) { exists(SemBound bound, IRFunction func | semBounded(getSemanticExpr(i), bound, delta, true, _) and b = getABoundIn(bound, func) and @@ -36,17 +36,21 @@ predicate boundedImpl(Instruction i, Instruction b, int delta) { bindingset[i] pragma[inline_late] -predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) } +predicate bounded1(Instruction i, Instruction b, QlBuiltins::BigInt delta) { + boundedImpl(i, b, delta) +} bindingset[b] pragma[inline_late] -predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) } +predicate bounded2(Instruction i, Instruction b, QlBuiltins::BigInt delta) { + boundedImpl(i, b, delta) +} bindingset[delta] predicate isInvalidPointerDerefSinkImpl( - int delta, Instruction i, AddressOperand addr, string operation + QlBuiltins::BigInt delta, Instruction i, AddressOperand addr, string operation ) { - delta >= 0 and + delta >= 0.toBigInt() and i.getAnOperand() = addr and ( i instanceof StoreInstruction and @@ -64,7 +68,7 @@ predicate isInvalidPointerDerefSinkImpl( */ pragma[inline] predicate isInvalidPointerDerefSink1(DataFlow::Node sink, Instruction i, string operation) { - exists(AddressOperand addr, int delta | + exists(AddressOperand addr, QlBuiltins::BigInt delta | bounded1(addr.getDef(), sink.asInstruction(), delta) and isInvalidPointerDerefSinkImpl(delta, i, addr, operation) ) @@ -72,7 +76,7 @@ predicate isInvalidPointerDerefSink1(DataFlow::Node sink, Instruction i, string pragma[inline] predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string operation) { - exists(AddressOperand addr, int delta | + exists(AddressOperand addr, QlBuiltins::BigInt delta | bounded2(addr.getDef(), sink.asInstruction(), delta) and isInvalidPointerDerefSinkImpl(delta, i, addr, operation) ) @@ -85,31 +89,33 @@ predicate arrayTypeCand(ArrayType arrayType) { bindingset[baseTypeSize] pragma[inline_late] -predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int size) { +predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, QlBuiltins::BigInt size) { arrayTypeCand(arr) and - arr.getByteSize() / baseTypeSize = size + (arr.getByteSize() / baseTypeSize).toBigInt() = size } bindingset[pai] pragma[inline_late] -predicate constantUpperBounded(PointerArithmeticInstruction pai, int delta) { +predicate constantUpperBounded(PointerArithmeticInstruction pai, QlBuiltins::BigInt delta) { semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true, _) } bindingset[pai, size] -predicate pointerArithOverflow0Impl(PointerArithmeticInstruction pai, int size, int delta) { - exists(int bound | +predicate pointerArithOverflow0Impl( + PointerArithmeticInstruction pai, QlBuiltins::BigInt size, QlBuiltins::BigInt delta +) { + exists(QlBuiltins::BigInt bound | constantUpperBounded(pai, bound) and delta = bound - size and - delta >= 0 and - size != 0 and - size != 1 + delta >= 0.toBigInt() and + size != 0.toBigInt() and + size != 1.toBigInt() ) } pragma[nomagic] -predicate pointerArithOverflow0(PointerArithmeticInstruction pai, int delta) { - exists(int size | +predicate pointerArithOverflow0(PointerArithmeticInstruction pai, QlBuiltins::BigInt delta) { + exists(QlBuiltins::BigInt size | arrayTypeHasSizes(_, pai.getElementSize(), size) and pointerArithOverflow0Impl(pai, size, delta) ) @@ -127,14 +133,16 @@ module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig { module PointerArithmeticToDerefFlow = DataFlow::Global; -predicate pointerArithOverflow(PointerArithmeticInstruction pai, int delta) { +predicate pointerArithOverflow(PointerArithmeticInstruction pai, QlBuiltins::BigInt delta) { pointerArithOverflow0(pai, delta) and PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _) } bindingset[v] -predicate finalPointerArithOverflow(Variable v, PointerArithmeticInstruction pai, int delta) { - exists(int size | +predicate finalPointerArithOverflow( + Variable v, PointerArithmeticInstruction pai, QlBuiltins::BigInt delta +) { + exists(QlBuiltins::BigInt size | arrayTypeHasSizes(pragma[only_bind_out](v.getUnspecifiedType()), pai.getElementSize(), size) and pointerArithOverflow0Impl(pai, size, delta) ) @@ -189,7 +197,8 @@ module ArrayAddressToDerefFlow = DataFlow::GlobalWithState 256 or - lowerBound(exp1).maximum(lowerBound(exp2)) - lowerBound(exp1).minimum(lowerBound(exp2)) > 256 + upperBound(exp1).maximum(upperBound(exp3)) - upperBound(exp1).minimum(upperBound(exp3)) > + 256.toBigInt() or + lowerBound(exp1).maximum(lowerBound(exp2)) - lowerBound(exp1).minimum(lowerBound(exp2)) > + 256.toBigInt() ) } @@ -146,10 +150,10 @@ predicate isDifferentResults( isRealRange(exp2) and isRealRange(exp3) ) and - exists(int i1, int i2, int i3 | - i1 in [lowerBound(exp1).floor() .. upperBound(exp1).floor()] and - i2 in [lowerBound(exp2).floor() .. upperBound(exp2).floor()] and - i3 in [lowerBound(exp3).floor() .. upperBound(exp3).floor()] and + exists(QlBuiltins::BigInt i1, QlBuiltins::BigInt i2, QlBuiltins::BigInt i3 | + i1 = lowerBound(exp1) + [0 .. (upperBound(exp1) - lowerBound(exp1)).toInt()].toBigInt() and + i2 = lowerBound(exp2) + [0 .. (upperBound(exp2) - lowerBound(exp2)).toInt()].toBigInt() and + i3 = lowerBound(exp3) + [0 .. (upperBound(exp3) - lowerBound(exp3)).toInt()].toBigInt() and ( op1 instanceof BitwiseOrExpr and op2 instanceof BitwiseAndExpr and diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.expected index 0a5c85dab00d..816cc25407bd 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.expected +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.expected @@ -1,44 +1,44 @@ -| bitshift.cpp:23:3:23:9 | ... <<= ... | 0.0 | 255.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | -| bitshift.cpp:25:5:25:11 | ... <<= ... | 0.0 | 240.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | -| bitshift.cpp:29:3:29:8 | ... << ... | 0.0 | 1020.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:32:3:32:9 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:35:3:35:9 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:38:3:38:22 | ... << ... | 0.0 | 32640.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:39:3:39:22 | ... << ... | 0.0 | 32640.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:40:3:40:22 | ... << ... | 0.0 | 32640.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:43:3:43:19 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:46:3:46:22 | ... << ... | 128.0 | 128.0 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:49:3:49:8 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:52:5:52:10 | ... << ... | 1.0 | 128.0 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:57:3:57:8 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:58:3:58:9 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:59:3:59:9 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:60:3:60:22 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:61:3:61:19 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:64:3:64:19 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:67:3:67:8 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:70:5:70:10 | ... << ... | 1.0 | 128.0 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:75:5:75:10 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:76:5:76:10 | ... << ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:90:3:90:9 | ... >>= ... | 0.0 | 63.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | -| bitshift.cpp:92:5:92:11 | ... >>= ... | 0.0 | 15.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | -| bitshift.cpp:96:3:96:8 | ... >> ... | 0.0 | 63.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:99:3:99:9 | ... >> ... | 0.0 | 0.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:103:3:103:9 | ... >> ... | 0.0 | 0.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:106:3:106:22 | ... >> ... | 0.0 | 63.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:107:3:107:22 | ... >> ... | 0.0 | 63.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:108:3:108:22 | ... >> ... | 0.0 | 63.0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:111:3:111:19 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:114:3:114:24 | ... >> ... | 32.0 | 32.0 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:117:3:117:10 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:120:5:120:12 | ... >> ... | 32.0 | 128.0 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:126:3:126:8 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:127:3:127:9 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:128:3:128:9 | ... >> ... | -1.0 | 0.0 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:129:3:129:22 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:130:3:130:19 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:133:3:133:21 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:136:3:136:10 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:139:5:139:12 | ... >> ... | 32.0 | 128.0 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:144:5:144:10 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | -| bitshift.cpp:145:5:145:10 | ... >> ... | -2.147483648E9 | 2.147483647E9 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:23:3:23:9 | ... <<= ... | 0 | 255 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | +| bitshift.cpp:25:5:25:11 | ... <<= ... | 0 | 240 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | +| bitshift.cpp:29:3:29:8 | ... << ... | 0 | 1020 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:32:3:32:9 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:35:3:35:9 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:38:3:38:22 | ... << ... | 0 | 32640 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:39:3:39:22 | ... << ... | 0 | 32640 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:40:3:40:22 | ... << ... | 0 | 32640 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:43:3:43:19 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:46:3:46:22 | ... << ... | 128 | 128 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:49:3:49:8 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:52:5:52:10 | ... << ... | 1 | 128 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:57:3:57:8 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:58:3:58:9 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:59:3:59:9 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:60:3:60:22 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:61:3:61:19 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:64:3:64:19 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:67:3:67:8 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:70:5:70:10 | ... << ... | 1 | 128 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:75:5:75:10 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:76:5:76:10 | ... << ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:90:3:90:9 | ... >>= ... | 0 | 63 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | +| bitshift.cpp:92:5:92:11 | ... >>= ... | 0 | 15 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | +| bitshift.cpp:96:3:96:8 | ... >> ... | 0 | 63 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:99:3:99:9 | ... >> ... | 0 | 0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:103:3:103:9 | ... >> ... | 0 | 0 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:106:3:106:22 | ... >> ... | 0 | 63 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:107:3:107:22 | ... >> ... | 0 | 63 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:108:3:108:22 | ... >> ... | 0 | 63 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:111:3:111:19 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:114:3:114:24 | ... >> ... | 32 | 32 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:117:3:117:10 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:120:5:120:12 | ... >> ... | 32 | 128 | file://:0:0:0:0 | int | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:126:3:126:8 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:127:3:127:9 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:128:3:128:9 | ... >> ... | 0 | 0 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:129:3:129:22 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:130:3:130:19 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:133:3:133:21 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:136:3:136:10 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:139:5:139:12 | ... >> ... | 32 | 128 | file://:0:0:0:0 | int | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:144:5:144:10 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | signed char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | +| bitshift.cpp:145:5:145:10 | ... >> ... | -2147483648 | 2147483647 | file://:0:0:0:0 | signed char | file://:0:0:0:0 | unsigned char | file://:0:0:0:0 | int | file://:0:0:0:0 | int | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.ql index 5429743abd5e..6f3e8abfb03f 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitshift/BitShiftRange.ql @@ -19,6 +19,6 @@ where or o instanceof AssignBitwiseOperation ) -select o, lowerBound(o), upperBound(o), getLOp(o).getUnderlyingType(), +select o, lowerBound(o).toString(), upperBound(o).toString(), getLOp(o).getUnderlyingType(), getROp(o).getUnderlyingType(), getLOp(o).getFullyConverted().getUnderlyingType(), getROp(o).getFullyConverted().getUnderlyingType() diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected index 22ad956469e4..f1674d460b9a 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.expected @@ -1,21 +1,21 @@ -| bitwiseand.cpp:7:3:7:8 | ... &= ... | 0.0 | 7.0 | -| bitwiseand.cpp:15:3:15:7 | ... & ... | 0.0 | 0.0 | -| bitwiseand.cpp:16:3:16:7 | ... & ... | 0.0 | 7.0 | -| bitwiseand.cpp:17:3:17:20 | ... & ... | 0.0 | 7.0 | -| bitwiseand.cpp:21:3:21:16 | ... & ... | 0.0 | 255.0 | -| bitwiseand.cpp:28:5:28:9 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:32:5:32:9 | ... & ... | 0.0 | 100.0 | -| bitwiseand.cpp:41:3:41:8 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:42:3:42:18 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:43:3:43:7 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:46:3:46:7 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:47:3:47:20 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:48:3:48:16 | ... & ... | 0.0 | 4.294967295E9 | -| bitwiseand.cpp:49:3:49:25 | ... & ... | -9.223372036854776E18 | 9.223372036854776E18 | -| bitwiseand.cpp:50:3:50:7 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:53:3:53:8 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:54:3:54:18 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:55:3:55:19 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:56:3:56:18 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:57:3:57:8 | ... & ... | -2.147483648E9 | 2.147483647E9 | -| bitwiseand.cpp:58:3:58:19 | ... & ... | -2.147483648E9 | 2.147483647E9 | +| bitwiseand.cpp:7:3:7:8 | ... &= ... | 0 | 7 | +| bitwiseand.cpp:15:3:15:7 | ... & ... | 0 | 0 | +| bitwiseand.cpp:16:3:16:7 | ... & ... | 0 | 7 | +| bitwiseand.cpp:17:3:17:20 | ... & ... | 0 | 7 | +| bitwiseand.cpp:21:3:21:16 | ... & ... | 0 | 255 | +| bitwiseand.cpp:28:5:28:9 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:32:5:32:9 | ... & ... | 0 | 100 | +| bitwiseand.cpp:41:3:41:8 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:42:3:42:18 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:43:3:43:7 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:46:3:46:7 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:47:3:47:20 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:48:3:48:16 | ... & ... | 0 | 4294967295 | +| bitwiseand.cpp:49:3:49:25 | ... & ... | -9223372036854775808 | 9223372036854775807 | +| bitwiseand.cpp:50:3:50:7 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:53:3:53:8 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:54:3:54:18 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:55:3:55:19 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:56:3:56:18 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:57:3:57:8 | ... & ... | -2147483648 | 2147483647 | +| bitwiseand.cpp:58:3:58:19 | ... & ... | -2147483648 | 2147483647 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql index 6521e8f0f610..021f5428e19f 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/bitwiseand/bitwiseand.ql @@ -1,8 +1,8 @@ import experimental.semmle.code.cpp.rangeanalysis.ExtendedRangeAnalysis -from Operation expr, float lower, float upper +from Operation expr, QlBuiltins::BigInt lower, QlBuiltins::BigInt upper where (expr instanceof BitwiseAndExpr or expr instanceof AssignAndExpr) and lower = lowerBound(expr) and upper = upperBound(expr) -select expr, lower, upper +select expr, lower.toString(), upper.toString() diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected index b43601c80886..e99f6e360fef 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.expected @@ -1,6 +1,6 @@ -| extended.cpp:4:14:4:14 | x | -2.147483648E9 | 2.147483647E9 | -| extended.cpp:4:18:4:18 | x | -2.147483648E9 | 2.147483647E9 | -| extended.cpp:5:3:5:6 | zero | 0.0 | 0.0 | -| extended.cpp:7:17:7:17 | x | -2.147483648E9 | 2.147483647E9 | -| extended.cpp:7:36:7:36 | x | -2.147483648E9 | 2.147483647E9 | -| extended.cpp:8:3:8:9 | nonzero | -2.147483648E9 | 2.147483647E9 | +| extended.cpp:4:14:4:14 | x | -2147483648 | 2147483647 | +| extended.cpp:4:18:4:18 | x | -2147483648 | 2147483647 | +| extended.cpp:5:3:5:6 | zero | 0 | 0 | +| extended.cpp:7:17:7:17 | x | -2147483648 | 2147483647 | +| extended.cpp:7:36:7:36 | x | -2147483648 | 2147483647 | +| extended.cpp:8:3:8:9 | nonzero | -2147483648 | 2147483647 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql index d6344e5d0629..b60e07f9f6af 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extended/extended.ql @@ -1,7 +1,7 @@ import experimental.semmle.code.cpp.rangeanalysis.ExtendedRangeAnalysis -from VariableAccess expr, float lower, float upper +from VariableAccess expr, QlBuiltins::BigInt lower, QlBuiltins::BigInt upper where lower = lowerBound(expr) and upper = upperBound(expr) -select expr, lower, upper +select expr, lower.toString(), upper.toString() diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected index e9133e191044..6b481dbecb77 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.expected @@ -1,9 +1,9 @@ -| extensibility.c:5:7:5:7 | x | -2.147483648E9 | 2.147483647E9 | -| extensibility.c:5:19:5:19 | x | -10.0 | 2.147483647E9 | -| extensibility.c:6:38:6:38 | x | -10.0 | 10.0 | -| extensibility.c:7:12:7:17 | result | 90.0 | 110.0 | -| extensibility.c:12:16:12:16 | x | -2.147483648E9 | 2.147483647E9 | -| extensibility.c:12:35:12:35 | x | -2.147483648E9 | 2.147483647E9 | -| extensibility.c:13:10:13:15 | result | 0.0 | 0.0 | -| extensibility.c:17:3:17:23 | magic_name_at_most_10 | -2.147483648E9 | 10.0 | -| extensibility.c:18:3:18:23 | magic_name_at_most_20 | -2.147483648E9 | 20.0 | +| extensibility.c:5:7:5:7 | x | -2147483648 | 2147483647 | +| extensibility.c:5:19:5:19 | x | -10 | 2147483647 | +| extensibility.c:6:38:6:38 | x | -10 | 10 | +| extensibility.c:7:12:7:17 | result | 90 | 110 | +| extensibility.c:12:16:12:16 | x | -2147483648 | 2147483647 | +| extensibility.c:12:35:12:35 | x | -2147483648 | 2147483647 | +| extensibility.c:13:10:13:15 | result | 0 | 0 | +| extensibility.c:17:3:17:23 | magic_name_at_most_10 | -2147483648 | 10 | +| extensibility.c:18:3:18:23 | magic_name_at_most_20 | -2147483648 | 20 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql index 0d110e67fa1e..92ccbfd5e878 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/extensibility/extensibility.ql @@ -6,8 +6,8 @@ import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisDefinit class CustomAddFunctionCall extends SimpleRangeAnalysisExpr, FunctionCall { CustomAddFunctionCall() { this.getTarget().hasGlobalName("custom_add_function") } - override float getLowerBounds() { - exists(float lower0, float lower1 | + override QlBuiltins::BigInt getLowerBounds() { + exists(QlBuiltins::BigInt lower0, QlBuiltins::BigInt lower1 | lower0 = getFullyConvertedLowerBounds(this.getArgument(0)) and lower1 = getFullyConvertedLowerBounds(this.getArgument(1)) and // Note: this rounds toward 0, not -Inf as it should @@ -15,8 +15,8 @@ class CustomAddFunctionCall extends SimpleRangeAnalysisExpr, FunctionCall { ) } - override float getUpperBounds() { - exists(float upper0, float upper1 | + override QlBuiltins::BigInt getUpperBounds() { + exists(QlBuiltins::BigInt upper0, QlBuiltins::BigInt upper1 | upper0 = getFullyConvertedUpperBounds(this.getArgument(0)) and upper1 = getFullyConvertedUpperBounds(this.getArgument(1)) and // Note: this rounds toward 0, not Inf as it should @@ -33,9 +33,9 @@ class SelfSub extends SimpleRangeAnalysisExpr, SubExpr { this.getRightOperand().(VariableAccess).getTarget() } - override float getLowerBounds() { result = 0 } + override QlBuiltins::BigInt getLowerBounds() { result = 0.toBigInt() } - override float getUpperBounds() { result = 0 } + override QlBuiltins::BigInt getUpperBounds() { result = 0.toBigInt() } override predicate dependsOnChild(Expr child) { child = this.getAnOperand() } } @@ -49,11 +49,11 @@ class SelfSub extends SimpleRangeAnalysisExpr, SubExpr { */ class MagicParameterName extends SimpleRangeAnalysisDefinition { Parameter p; - float value; + QlBuiltins::BigInt value; MagicParameterName() { this.definedByParameter(p) and - value = p.getName().regexpCapture("magic_name_at_most_(\\d+)", 1).toFloat() + value = p.getName().regexpCapture("magic_name_at_most_(\\d+)", 1).toBigInt() } override predicate hasRangeInformationFor(StackVariable v) { v = p } @@ -63,19 +63,19 @@ class MagicParameterName extends SimpleRangeAnalysisDefinition { none() } - override float getLowerBounds(StackVariable var) { + override QlBuiltins::BigInt getLowerBounds(StackVariable var) { var = p and result = typeLowerBound(p.getUnspecifiedType()) } - override float getUpperBounds(StackVariable var) { + override QlBuiltins::BigInt getUpperBounds(StackVariable var) { var = p and result = value } } -from VariableAccess expr, float lower, float upper +from VariableAccess expr, QlBuiltins::BigInt lower, QlBuiltins::BigInt upper where lower = lowerBound(expr) and upper = upperBound(expr) -select expr, lower, upper +select expr, lower.toString(), upper.toString() diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.expected index f714ac312ea7..6fe0ec239b62 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.expected +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.expected @@ -1,2 +1,2 @@ -| test.cpp:4:3:4:8 | call to strlen | 7.0 | 7.0 | -| test.cpp:5:3:5:8 | call to strlen | 1.8446744073709552E19 | 0.0 | +| test.cpp:4:3:4:8 | call to strlen | 7 | 7 | +| test.cpp:5:3:5:8 | call to strlen | 18446744073709551615 | 0 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.ql index c77b20786109..59016bf0d48b 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/strlenliteral/StrlenLiteralRange.ql @@ -3,4 +3,4 @@ import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import experimental.semmle.code.cpp.rangeanalysis.extensions.StrlenLiteralRangeExpr from FunctionCall fc -select fc, upperBound(fc), lowerBound(fc) +select fc, upperBound(fc).toString(), lowerBound(fc).toString() diff --git a/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql b/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql index 229cc240c9ed..a0bc0c71638d 100644 --- a/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql +++ b/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql @@ -2,14 +2,13 @@ import cpp import codeql.rangeanalysis.ModulusAnalysis import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation -import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific import semmle.code.cpp.ir.IR as IR import TestUtilities.InlineExpectationsTest -module ModulusAnalysisInstantiated = ModulusAnalysis; +module ModulusAnalysisInstantiated = ModulusAnalysis; module ModulusAnalysisTest implements TestSig { string getARelevantTag() { result = "mod" } @@ -29,9 +28,9 @@ module ModulusAnalysisTest implements TestSig { import MakeTest private string getAModString(SemExpr e) { - exists(SemBound b, int delta, int mod | + exists(SemBound b, QlBuiltins::BigInt delta, QlBuiltins::BigInt mod | ModulusAnalysisInstantiated::exprModulus(e, b, delta, mod) and result = b.toString() + "," + delta.toString() + "," + mod.toString() and - not (delta = 0 and mod = 0) + not (delta = 0.toBigInt() and mod = 0.toBigInt()) ) } diff --git a/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.ql b/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.ql index b5a86c23d97c..60f3f2148a1c 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.ql +++ b/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.ql @@ -29,25 +29,25 @@ private string getDirectionString(boolean d) { } bindingset[value] -private string getOffsetString(float value) { - if value >= 0 then result = "+" + value.toString() else result = value.toString() +private string getOffsetString(QlBuiltins::BigInt value) { + if value >= 0.toBigInt() then result = "+" + value.toString() else result = value.toString() } bindingset[s] string quote(string s) { if s.matches("% %") then result = "\"" + s + "\"" else result = s } bindingset[delta] -private string getBoundString(SemBound b, float delta) { +private string getBoundString(SemBound b, QlBuiltins::BigInt delta) { b instanceof SemZeroBound and result = delta.toString() or result = strictconcat(b.(SemSsaBound).getAVariable().toString(), " | ") + getOffsetString(delta) } private string getARangeString(SemExpr e) { - exists(SemBound b, float delta, boolean upper | + exists(SemBound b, QlBuiltins::BigInt delta, boolean upper | semBounded(e, b, delta, upper, _) and if semBounded(e, b, delta, upper.booleanNot(), _) - then delta != 0 and result = "==" + getBoundString(b, delta) + then delta != 0.toBigInt() and result = "==" + getBoundString(b, delta) else result = getDirectionString(upper) + getBoundString(b, delta) ) } diff --git a/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp b/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp index 7b359a046d81..29e9bf80cfb4 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp +++ b/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp @@ -741,8 +741,8 @@ unsigned long mult_rounding() { range(y); // $ range===1000000003 range(x); // $ range===1000000003 xy = x * y; - range(xy); // $ range===1000000006000000000 - return xy; // BUG: upper bound should be >= 1000000006000000009UL + range(xy); // $ range===1000000006000000009 + return xy; } unsigned long mult_overflow() { diff --git a/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql b/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql index cba373a60a12..0ce99366e18e 100644 --- a/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql +++ b/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql @@ -1,13 +1,12 @@ import cpp import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic -import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific import semmle.code.cpp.ir.IR as IR import TestUtilities.InlineExpectationsTest -module SignAnalysisInstantiated = SignAnalysis; +module SignAnalysisInstantiated = SignAnalysis; module SignAnalysisTest implements TestSig { string getARelevantTag() { result = "sign" } diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected index 112b6cb02014..482073673d8a 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected @@ -486,13 +486,13 @@ | test.c:470:3:470:4 | xy | 0 | | test.c:470:8:470:8 | x | 1000000003 | | test.c:470:12:470:12 | y | 1000000003 | -| test.c:471:10:471:11 | xy | 1000000006000000000 | +| test.c:471:10:471:11 | xy | 1000000006000000009 | | test.c:476:3:476:3 | x | 0 | | test.c:477:3:477:3 | y | 0 | | test.c:478:3:478:4 | xy | 0 | | test.c:478:8:478:8 | x | 274177 | | test.c:478:12:478:12 | y | 67280421310721 | -| test.c:479:10:479:11 | xy | 18446744073709551616 | +| test.c:479:10:479:11 | xy | 0 | | test.c:483:7:483:8 | ui | 0 | | test.c:484:43:484:44 | ui | 10 | | test.c:484:48:484:49 | ui | 10 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected index f012490f1156..d46d390c0497 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.expected @@ -1,19 +1,19 @@ -| test.c:154:10:154:40 | ... ? ... : ... | -1.0 | 1.0 | -1.0 | -| test.c:357:8:357:23 | ... ? ... : ... | 0.0 | 0.0 | 10.0 | -| test.c:358:8:358:24 | ... ? ... : ... | 0.0 | 10.0 | 0.0 | -| test.c:366:10:366:15 | ... ? ... : ... | 0.0 | 0.0 | 5.0 | -| test.c:367:10:367:17 | ... ? ... : ... | 0.0 | 0.0 | 500.0 | -| test.c:368:10:368:21 | ... ? ... : ... | 1.0 | 1.0 | 500.0 | -| test.c:369:10:369:36 | ... ? ... : ... | 0.0 | 1.0 | 5.0 | -| test.c:370:10:370:38 | ... ? ... : ... | 0.0 | 1.0 | 500.0 | -| test.c:371:10:371:39 | ... ? ... : ... | 1.0 | 1.0 | 500.0 | -| test.c:379:8:379:24 | ... ? ... : ... | 101.0 | 101.0 | 110.0 | -| test.c:380:8:380:25 | ... ? ... : ... | 101.0 | 110.0 | 101.0 | -| test.c:385:10:385:21 | ... ? ... : ... | 0.0 | 0.0 | 5.0 | -| test.c:386:10:386:21 | ... ? ... : ... | 100.0 | 100.0 | 5.0 | -| test.c:387:10:387:38 | ... ? ... : ... | 0.0 | 100.0 | 5.0 | -| test.c:394:20:394:36 | ... ? ... : ... | 0.0 | 0.0 | 100.0 | -| test.c:606:5:606:14 | ... ? ... : ... | 0.0 | 1.0 | 0.0 | -| test.c:607:5:607:14 | ... ? ... : ... | 0.0 | 0.0 | 1.0 | -| test.cpp:121:3:121:12 | ... ? ... : ... | 0.0 | 1.0 | 0.0 | -| test.cpp:122:3:122:12 | ... ? ... : ... | 0.0 | 0.0 | 1.0 | +| test.c:154:10:154:40 | ... ? ... : ... | -1 | 1 | -1 | +| test.c:357:8:357:23 | ... ? ... : ... | 0 | 0 | 10 | +| test.c:358:8:358:24 | ... ? ... : ... | 0 | 10 | 0 | +| test.c:366:10:366:15 | ... ? ... : ... | 0 | 0 | 5 | +| test.c:367:10:367:17 | ... ? ... : ... | 0 | 0 | 500 | +| test.c:368:10:368:21 | ... ? ... : ... | 1 | 1 | 500 | +| test.c:369:10:369:36 | ... ? ... : ... | 0 | 1 | 5 | +| test.c:370:10:370:38 | ... ? ... : ... | 0 | 1 | 500 | +| test.c:371:10:371:39 | ... ? ... : ... | 1 | 1 | 500 | +| test.c:379:8:379:24 | ... ? ... : ... | 101 | 101 | 110 | +| test.c:380:8:380:25 | ... ? ... : ... | 101 | 110 | 101 | +| test.c:385:10:385:21 | ... ? ... : ... | 0 | 0 | 5 | +| test.c:386:10:386:21 | ... ? ... : ... | 100 | 100 | 5 | +| test.c:387:10:387:38 | ... ? ... : ... | 0 | 100 | 5 | +| test.c:394:20:394:36 | ... ? ... : ... | 0 | 0 | 100 | +| test.c:606:5:606:14 | ... ? ... : ... | 0 | 1 | 0 | +| test.c:607:5:607:14 | ... ? ... : ... | 0 | 0 | 1 | +| test.cpp:121:3:121:12 | ... ? ... : ... | 0 | 1 | 0 | +| test.cpp:122:3:122:12 | ... ? ... : ... | 0 | 0 | 1 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.ql b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.ql index f4065881bcc9..d1a7839a84f6 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryLower.ql @@ -2,4 +2,5 @@ import cpp import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis from ConditionalExpr ce -select ce, lowerBound(ce), lowerBound(ce.getThen()), lowerBound(ce.getElse()) +select ce, lowerBound(ce).toString(), lowerBound(ce.getThen()).toString(), + lowerBound(ce.getElse()).toString() diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected index 8a387c3ae464..527a4d4381d3 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.expected @@ -1,19 +1,19 @@ -| test.c:154:10:154:40 | ... ? ... : ... | 2.147483647E9 | 2.147483647E9 | -1.0 | -| test.c:357:8:357:23 | ... ? ... : ... | 99.0 | 99.0 | 10.0 | -| test.c:358:8:358:24 | ... ? ... : ... | 99.0 | 10.0 | 99.0 | -| test.c:366:10:366:15 | ... ? ... : ... | 299.0 | 299.0 | 5.0 | -| test.c:367:10:367:17 | ... ? ... : ... | 500.0 | 299.0 | 500.0 | -| test.c:368:10:368:21 | ... ? ... : ... | 300.0 | 300.0 | 500.0 | -| test.c:369:10:369:36 | ... ? ... : ... | 255.0 | 300.0 | 5.0 | -| test.c:370:10:370:38 | ... ? ... : ... | 500.0 | 300.0 | 500.0 | -| test.c:371:10:371:39 | ... ? ... : ... | 300.0 | 300.0 | 500.0 | -| test.c:379:8:379:24 | ... ? ... : ... | 4.294967295E9 | 4.294967295E9 | 110.0 | -| test.c:380:8:380:25 | ... ? ... : ... | 4.294967295E9 | 110.0 | 4.294967295E9 | -| test.c:385:10:385:21 | ... ? ... : ... | 4.294967295E9 | 4.294967295E9 | 5.0 | -| test.c:386:10:386:21 | ... ? ... : ... | 4.294967295E9 | 4.294967295E9 | 5.0 | -| test.c:387:10:387:38 | ... ? ... : ... | 255.0 | 4.294967295E9 | 5.0 | -| test.c:394:20:394:36 | ... ? ... : ... | 100.0 | 99.0 | 100.0 | -| test.c:606:5:606:14 | ... ? ... : ... | 32767.0 | 32767.0 | 0.0 | -| test.c:607:5:607:14 | ... ? ... : ... | 32767.0 | 0.0 | 32767.0 | -| test.cpp:121:3:121:12 | ... ? ... : ... | 32767.0 | 32767.0 | 0.0 | -| test.cpp:122:3:122:12 | ... ? ... : ... | 32767.0 | 0.0 | 32767.0 | +| test.c:154:10:154:40 | ... ? ... : ... | 2147483647 | 2147483647 | -1 | +| test.c:357:8:357:23 | ... ? ... : ... | 99 | 99 | 10 | +| test.c:358:8:358:24 | ... ? ... : ... | 99 | 10 | 99 | +| test.c:366:10:366:15 | ... ? ... : ... | 299 | 299 | 5 | +| test.c:367:10:367:17 | ... ? ... : ... | 500 | 299 | 500 | +| test.c:368:10:368:21 | ... ? ... : ... | 300 | 300 | 500 | +| test.c:369:10:369:36 | ... ? ... : ... | 255 | 300 | 5 | +| test.c:370:10:370:38 | ... ? ... : ... | 500 | 300 | 500 | +| test.c:371:10:371:39 | ... ? ... : ... | 300 | 300 | 500 | +| test.c:379:8:379:24 | ... ? ... : ... | 4294967295 | 4294967295 | 110 | +| test.c:380:8:380:25 | ... ? ... : ... | 4294967295 | 110 | 4294967295 | +| test.c:385:10:385:21 | ... ? ... : ... | 4294967295 | 4294967295 | 5 | +| test.c:386:10:386:21 | ... ? ... : ... | 4294967295 | 4294967295 | 5 | +| test.c:387:10:387:38 | ... ? ... : ... | 255 | 4294967295 | 5 | +| test.c:394:20:394:36 | ... ? ... : ... | 100 | 99 | 100 | +| test.c:606:5:606:14 | ... ? ... : ... | 32767 | 32767 | 0 | +| test.c:607:5:607:14 | ... ? ... : ... | 32767 | 0 | 32767 | +| test.cpp:121:3:121:12 | ... ? ... : ... | 32767 | 32767 | 0 | +| test.cpp:122:3:122:12 | ... ? ... : ... | 32767 | 0 | 32767 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.ql b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.ql index 409735829361..6eb11702965f 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/ternaryUpper.ql @@ -2,4 +2,4 @@ import cpp import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis from ConditionalExpr ce -select ce, upperBound(ce), upperBound(ce.getThen()), upperBound(ce.getElse()) +select ce, upperBound(ce).toString(), upperBound(ce.getThen()), upperBound(ce.getElse()).toString() diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c index 8c7978ac4aa6..6a844e116cde 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c @@ -468,7 +468,7 @@ unsigned long mult_rounding() { unsigned long x, y, xy; x = y = 1000000003UL; // 1e9 + 3 xy = x * y; - return xy; // BUG: upper bound should be >= 1000000006000000009UL + return xy; // = 1000000006000000009UL } unsigned long mult_overflow() { diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c index fd1bc655051d..6e4c063b8cfb 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c @@ -401,8 +401,8 @@ void mult_rounding() { // are no PointlessComparison false positives in these tests because alerts // are suppressed when ulp() < 1, which roughly means that the number is // larger than 2^53. - if (x * y < xy) {} // always false [NOT DETECTED] - if (x * y > xy) {} // always false [NOT DETECTED] + if (x * y < xy) {} // always false + if (x * y > xy) {} // always false } void mult_overflow() { @@ -411,7 +411,7 @@ void mult_overflow() { // to 64-bit unsigned. x = 274177UL; y = 67280421310721UL; - if (x * y == 1) {} // always true [BUG: reported as always false] + if (x * y == 1) {} // always true [NOT DETECTED] // This bug appears to be caused by // `RangeAnalysisUtils::typeUpperBound(unsigned long)` having a result of diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp index 7b67f77ad443..b9824a27ece8 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp @@ -6,7 +6,7 @@ struct A { const int int_member = 0; A(int n) : int_member(n) { if(int_member <= 10) { - + } } }; @@ -34,12 +34,12 @@ int extreme_values(void) unsigned long long int y = 0xFFFFFFFFFFFF; if (x >> 1 >= 0xFFFFFFFFFFFFFFFF) {} // always false - if (x >> 1 >= 0x8000000000000000) {} // always false [NOT DETECTED] - if (x >> 1 >= 0x7FFFFFFFFFFFFFFF) {} // always true [NOT DETECTED] - if (x >> 1 >= 0xFFFFFFFFFFFFFFF) {} // always true [NOT DETECTED] - - if (y >> 1 >= 0xFFFFFFFFFFFF) {} // always false [INCORRECT MESSAGE] - if (y >> 1 >= 0x800000000000) {} // always false [INCORRECT MESSAGE] - if (y >> 1 >= 0x7FFFFFFFFFFF) {} // always true [INCORRECT MESSAGE] - if (y >> 1 >= 0xFFFFFFFFFFF) {} // always true [INCORRECT MESSAGE] + if (x >> 1 >= 0x8000000000000000) {} // always false + if (x >> 1 >= 0x7FFFFFFFFFFFFFFF) {} // always true + if (x >> 1 >= 0xFFFFFFFFFFFFFFF) {} // always true + + if (y >> 1 >= 0xFFFFFFFFFFFF) {} // always false + if (y >> 1 >= 0x800000000000) {} // always false + if (y >> 1 >= 0x7FFFFFFFFFFF) {} // always true + if (y >> 1 >= 0xFFFFFFFFFFF) {} // always true } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected index 6c273b985eeb..29c5929dfb73 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected @@ -43,11 +43,15 @@ | PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. | | PointlessComparison.c:388:10:388:21 | ... > ... | Comparison is always false because ... * ... <= 408. | | PointlessComparison.c:391:12:391:20 | ... < ... | Comparison is always false because ... * ... >= 6. | -| PointlessComparison.c:414:7:414:16 | ... == ... | Comparison is always false because ... * ... >= 18446744073709551616. | -| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854775808. | -| PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | -| PointlessComparison.cpp:42:6:42:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | -| PointlessComparison.cpp:43:6:43:29 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327.5. | -| PointlessComparison.cpp:44:6:44:28 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327.5. | +| PointlessComparison.c:404:7:404:16 | ... < ... | Comparison is always false because ... * ... >= 1000000006000000009 and 1000000006000000009 >= xy. | +| PointlessComparison.c:405:7:405:16 | ... > ... | Comparison is always false because ... * ... <= 1000000006000000009 and 1000000006000000009 <= xy. | +| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854775807. | +| PointlessComparison.cpp:37:6:37:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854775807. | +| PointlessComparison.cpp:38:6:38:33 | ... >= ... | Comparison is always true because ... >> ... >= 9223372036854775807. | +| PointlessComparison.cpp:39:6:39:32 | ... >= ... | Comparison is always true because ... >> ... >= 9223372036854775807. | +| PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327. | +| PointlessComparison.cpp:42:6:42:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327. | +| PointlessComparison.cpp:43:6:43:29 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327. | +| PointlessComparison.cpp:44:6:44:28 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327. | | RegressionTests.cpp:57:7:57:22 | ... <= ... | Comparison is always true because * ... <= 4294967295. | | Templates.cpp:9:10:9:24 | ... <= ... | Comparison is always true because local <= 32767. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.ql b/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.ql index 50baab4bfa7a..74b67dcd9b61 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.ql +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.ql @@ -8,19 +8,19 @@ module AllocationToInvalidPointerTest implements TestSig { string getARelevantTag() { result = "alloc" } predicate hasActualResult(Location location, string element, string tag, string value) { - exists(DataFlow::Node allocation, PointerAddInstruction pai, int delta | + exists(DataFlow::Node allocation, PointerAddInstruction pai, QlBuiltins::BigInt delta | pointerAddInstructionHasBounds(allocation, pai, _, delta) and location = pai.getLocation() and element = pai.toString() and tag = "alloc" | - delta > 0 and + delta > 0.toBigInt() and value = "L" + allocation.getLocation().getStartLine().toString() + "+" + delta.toString() or - delta = 0 and + delta = 0.toBigInt() and value = "L" + allocation.getLocation().getStartLine().toString() or - delta < 0 and + delta < 0.toBigInt() and value = "L" + allocation.getLocation().getStartLine().toString() + "-" + (-delta).toString() ) } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.ql b/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.ql index c4d9be5cb8bd..133c7952a5bc 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.ql +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.ql @@ -48,8 +48,8 @@ module InvalidPointerToDereferenceTest implements TestSig { predicate hasActualResult(Location location, string element, string tag, string value) { exists( - DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation, int delta, - string value1, string value2 + DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation, + QlBuiltins::BigInt delta, string value1, string value2 | operationIsOffBy(_, _, derefSource, derefSink, _, operation, delta) and location = operation.getLocation() and @@ -65,13 +65,13 @@ module InvalidPointerToDereferenceTest implements TestSig { value1 = case1(derefSource, derefSink, operation) ) and ( - delta > 0 and + delta > 0.toBigInt() and value2 = "+" + delta or - delta = 0 and + delta = 0.toBigInt() and value2 = "" or - delta < 0 and + delta < 0.toBigInt() and value2 = "-" + (-delta) ) ) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll index 08826b7ae8f1..a6b4e83b917c 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll @@ -20,10 +20,10 @@ abstract class Bound extends TBound { abstract string toString(); /** Gets an expression that equals this bound plus `delta`. */ - abstract Expr getExpr(int delta); + abstract Expr getExpr(QlBuiltins::BigInt delta); /** Gets an expression that equals this bound. */ - Expr getExpr() { result = this.getExpr(0) } + Expr getExpr() { result = this.getExpr(0.toBigInt()) } /** Gets the location of this bound. */ abstract Location getLocation(); @@ -36,7 +36,9 @@ abstract class Bound extends TBound { class ZeroBound extends Bound, TBoundZero { override string toString() { result = "0" } - override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta } + override Expr getExpr(QlBuiltins::BigInt delta) { + result.(ConstantIntegerExpr).getIntValue() = delta + } override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) } } @@ -50,7 +52,9 @@ class SsaBound extends Bound, TBoundSsa { override string toString() { result = this.getSsa().toString() } - override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 } + override Expr getExpr(QlBuiltins::BigInt delta) { + result = this.getSsa().getAUse() and delta = 0.toBigInt() + } override Location getLocation() { result = this.getSsa().getLocation() } } @@ -62,7 +66,9 @@ class SsaBound extends Bound, TBoundSsa { class ExprBound extends Bound, TBoundExpr { override string toString() { result = this.getExpr().toString() } - override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 } + override Expr getExpr(QlBuiltins::BigInt delta) { + this = TBoundExpr(result) and delta = 0.toBigInt() + } override Location getLocation() { result = this.getExpr().getLocation() } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll index 5b2a39ad6c9e..acd820d62c8f 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll @@ -11,7 +11,9 @@ private import internal.rangeanalysis.SsaReadPositionCommon /** * Holds if `e + delta` equals `v` at `pos`. */ -private predicate valueFlowStepSsa(SsaVariable v, SsaReadPosition pos, Expr e, int delta) { +private predicate valueFlowStepSsa( + SsaVariable v, SsaReadPosition pos, Expr e, QlBuiltins::BigInt delta +) { ssaUpdateStep(v, e, delta) and pos.hasReadOfVar(v) or exists(Guard guard, boolean testIsTrue | @@ -47,17 +49,17 @@ private predicate nonConstSubtraction(Expr sub, Expr larg, Expr rarg) { } /** Gets an expression that is the remainder modulo `mod` of `arg`. */ -private Expr modExpr(Expr arg, int mod) { +private Expr modExpr(Expr arg, QlBuiltins::BigInt mod) { exists(RemExpr rem | result = rem and arg = rem.getLeftOperand() and rem.getRightOperand().(ConstantIntegerExpr).getIntValue() = mod and - mod >= 2 + mod >= 2.toBigInt() ) or exists(ConstantIntegerExpr c | - mod = 2.pow([1 .. 30]) and - c.getIntValue() = mod - 1 and + mod = 2.toBigInt().pow([1 .. 30]) and + c.getIntValue() = mod - 1.toBigInt() and result.(BitwiseAndExpr).hasOperands(arg, c) ) } @@ -66,8 +68,10 @@ private Expr modExpr(Expr arg, int mod) { * Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on * its `testIsTrue` branch. */ -private Guard moduloCheck(SsaVariable v, int val, int mod, boolean testIsTrue) { - exists(Expr rem, ConstantIntegerExpr c, int r, boolean polarity | +private Guard moduloCheck( + SsaVariable v, QlBuiltins::BigInt val, QlBuiltins::BigInt mod, boolean testIsTrue +) { + exists(Expr rem, ConstantIntegerExpr c, QlBuiltins::BigInt r, boolean polarity | result.isEquality(rem, c, polarity) and c.getIntValue() = r and rem = modExpr(v.getAUse(), mod) and @@ -75,9 +79,9 @@ private Guard moduloCheck(SsaVariable v, int val, int mod, boolean testIsTrue) { testIsTrue = polarity and val = r or testIsTrue = polarity.booleanNot() and - mod = 2 and - val = 1 - r and - (r = 0 or r = 1) + mod = 2.toBigInt() and + val = 1.toBigInt() - r and + (r = 0.toBigInt() or r = 1.toBigInt()) ) ) } @@ -85,7 +89,9 @@ private Guard moduloCheck(SsaVariable v, int val, int mod, boolean testIsTrue) { /** * Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`. */ -private predicate moduloGuardedRead(SsaVariable v, SsaReadPosition pos, int val, int mod) { +private predicate moduloGuardedRead( + SsaVariable v, SsaReadPosition pos, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(Guard guard, boolean testIsTrue | pos.hasReadOfVar(v) and guard = moduloCheck(v, val, mod, testIsTrue) and @@ -101,13 +107,14 @@ private predicate andmaskFactor(int mask, int factor) { } /** Holds if `e` is evenly divisible by `factor`. */ -private predicate evenlyDivisibleExpr(Expr e, int factor) { - exists(ConstantIntegerExpr c, int k | k = c.getIntValue() | - e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2 +private predicate evenlyDivisibleExpr(Expr e, QlBuiltins::BigInt factor) { + exists(ConstantIntegerExpr c, QlBuiltins::BigInt k | k = c.getIntValue() | + e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2.toBigInt() or - e.(LeftShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0 + e.(LeftShiftExpr).getRhs() = c and factor = 2.toBigInt().pow(k.toInt()) and k > 0.toBigInt() or - e.(BitwiseAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f)) + e.(BitwiseAndExpr).getAnOperand() = c and + factor = max(int f | andmaskFactor(k.toInt(), f)).toBigInt() ) } @@ -118,31 +125,33 @@ private predicate evenlyDivisibleExpr(Expr e, int factor) { * the range `[0 .. mod-1]`. */ bindingset[val, mod] -private int remainder(int val, int mod) { - mod = 0 and result = val +private QlBuiltins::BigInt remainder(QlBuiltins::BigInt val, QlBuiltins::BigInt mod) { + mod = 0.toBigInt() and result = val or - mod > 1 and result = ((val % mod) + mod) % mod + mod > 1.toBigInt() and result = ((val % mod) + mod) % mod } /** * Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`. */ private predicate phiSelfModulus( - SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, int mod + SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, QlBuiltins::BigInt mod ) { - exists(SsaBound phibound, int v, int m | + exists(SsaBound phibound, QlBuiltins::BigInt v, QlBuiltins::BigInt m | edge.phiInput(phi, inp) and phibound.getSsa() = phi and ssaModulus(inp, edge, phibound, v, m) and mod = m.gcd(v) and - mod != 1 + mod != 1.toBigInt() ) } /** * Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`. */ -private predicate phiModulusInit(SsaPhiNode phi, Bound b, int val, int mod) { +private predicate phiModulusInit( + SsaPhiNode phi, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(SsaVariable inp, SsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) and ssaModulus(inp, edge, b, val, mod) @@ -152,22 +161,26 @@ private predicate phiModulusInit(SsaPhiNode phi, Bound b, int val, int mod) { /** * Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`. */ -private predicate phiModulusRankStep(SsaPhiNode phi, Bound b, int val, int mod, int rix) { +private predicate phiModulusRankStep( + SsaPhiNode phi, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod, int rix +) { rix = 0 and phiModulusInit(phi, b, val, mod) or - exists(SsaVariable inp, SsaReadPositionPhiInputEdge edge, int v1, int m1 | - mod != 1 and + exists( + SsaVariable inp, SsaReadPositionPhiInputEdge edge, QlBuiltins::BigInt v1, QlBuiltins::BigInt m1 + | + mod != 1.toBigInt() and val = remainder(v1, mod) | - exists(int v2, int m2 | + exists(QlBuiltins::BigInt v2, QlBuiltins::BigInt m2 | rankedPhiInput(phi, inp, edge, rix) and phiModulusRankStep(phi, b, v1, m1, rix - 1) and ssaModulus(inp, edge, b, v2, m2) and mod = m1.gcd(m2).gcd(v1 - v2) ) or - exists(int m2 | + exists(QlBuiltins::BigInt m2 | rankedPhiInput(phi, inp, edge, rix) and phiModulusRankStep(phi, b, v1, m1, rix - 1) and phiSelfModulus(phi, inp, edge, m2) and @@ -179,7 +192,7 @@ private predicate phiModulusRankStep(SsaPhiNode phi, Bound b, int val, int mod, /** * Holds if `phi` is equal to `b + val` modulo `mod`. */ -private predicate phiModulus(SsaPhiNode phi, Bound b, int val, int mod) { +private predicate phiModulus(SsaPhiNode phi, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod) { exists(int r | maxPhiInputRank(phi, r) and phiModulusRankStep(phi, b, val, mod, r) @@ -189,12 +202,14 @@ private predicate phiModulus(SsaPhiNode phi, Bound b, int val, int mod) { /** * Holds if `v` at `pos` is equal to `b + val` modulo `mod`. */ -private predicate ssaModulus(SsaVariable v, SsaReadPosition pos, Bound b, int val, int mod) { +private predicate ssaModulus( + SsaVariable v, SsaReadPosition pos, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { phiModulus(v, b, val, mod) and pos.hasReadOfVar(v) or - b.(SsaBound).getSsa() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0 + b.(SsaBound).getSsa() = v and pos.hasReadOfVar(v) and val = 0.toBigInt() and mod = 0.toBigInt() or - exists(Expr e, int val0, int delta | + exists(Expr e, QlBuiltins::BigInt val0, QlBuiltins::BigInt delta | exprModulus(e, b, val0, mod) and valueFlowStepSsa(v, pos, e, delta) and val = remainder(val0 + delta, mod) @@ -211,10 +226,10 @@ private predicate ssaModulus(SsaVariable v, SsaReadPosition pos, Bound b, int va * - `mod > 1`: `val` lies within the range `[0 .. mod-1]`. */ cached -predicate exprModulus(Expr e, Bound b, int val, int mod) { - e = b.getExpr(val) and mod = 0 +predicate exprModulus(Expr e, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod) { + e = b.getExpr(val) and mod = 0.toBigInt() or - evenlyDivisibleExpr(e, mod) and val = 0 and b instanceof ZeroBound + evenlyDivisibleExpr(e, mod) and val = 0.toBigInt() and b instanceof ZeroBound or exists(SsaVariable v, SsaReadPositionBlock bb | ssaModulus(v, bb, b, val, mod) and @@ -222,26 +237,32 @@ predicate exprModulus(Expr e, Bound b, int val, int mod) { getABasicBlockExpr(bb.getBlock()) = e ) or - exists(Expr mid, int val0, int delta | + exists(Expr mid, QlBuiltins::BigInt val0, QlBuiltins::BigInt delta | exprModulus(mid, b, val0, mod) and valueFlowStep(e, mid, delta) and val = remainder(val0 + delta, mod) ) or - exists(ConditionalExpr cond, int v1, int v2, int m1, int m2 | + exists( + ConditionalExpr cond, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt m1, + QlBuiltins::BigInt m2 + | cond = e and condExprBranchModulus(cond, true, b, v1, m1) and condExprBranchModulus(cond, false, b, v2, m2) and mod = m1.gcd(m2).gcd(v1 - v2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1, mod) ) or - exists(Bound b1, Bound b2, int v1, int v2, int m1, int m2 | + exists( + Bound b1, Bound b2, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt m1, + QlBuiltins::BigInt m2 + | addModulus(e, true, b1, v1, m1) and addModulus(e, false, b2, v2, m2) and mod = m1.gcd(m2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1 + v2, mod) | b = b1 and b2 instanceof ZeroBound @@ -249,22 +270,26 @@ predicate exprModulus(Expr e, Bound b, int val, int mod) { b = b2 and b1 instanceof ZeroBound ) or - exists(int v1, int v2, int m1, int m2 | + exists( + QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt m1, QlBuiltins::BigInt m2 + | subModulus(e, true, b, v1, m1) and subModulus(e, false, any(ZeroBound zb), v2, m2) and mod = m1.gcd(m2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1 - v2, mod) ) } private predicate condExprBranchModulus( - ConditionalExpr cond, boolean branch, Bound b, int val, int mod + ConditionalExpr cond, boolean branch, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod ) { exprModulus(cond.getBranchExpr(branch), b, val, mod) } -private predicate addModulus(Expr add, boolean isLeft, Bound b, int val, int mod) { +private predicate addModulus( + Expr add, boolean isLeft, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(Expr larg, Expr rarg | nonConstAddition(add, larg, rarg) | exprModulus(larg, b, val, mod) and isLeft = true or @@ -272,7 +297,9 @@ private predicate addModulus(Expr add, boolean isLeft, Bound b, int val, int mod ) } -private predicate subModulus(Expr sub, boolean isLeft, Bound b, int val, int mod) { +private predicate subModulus( + Expr sub, boolean isLeft, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(Expr larg, Expr rarg | nonConstSubtraction(sub, larg, rarg) | exprModulus(larg, b, val, mod) and isLeft = true or diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll index e3f5deb98989..35bf9e02a9b2 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ConstantUtils.qll @@ -22,8 +22,8 @@ predicate systemArrayLengthAccess(PropertyAccess pa) { * - a read of a compile time constant with integer value `val`, or * - a read of the `Length` of an array with `val` lengths. */ -private predicate constantIntegerExpr(ExprNode e, int val) { - e.getValue().toInt() = val +private predicate constantIntegerExpr(ExprNode e, QlBuiltins::BigInt val) { + e.getValue().toBigInt() = val or exists(ExprNode src | e = getAnExplicitDefinitionRead(src) and @@ -33,25 +33,26 @@ private predicate constantIntegerExpr(ExprNode e, int val) { isArrayLengthAccess(e, val) } -private int getArrayLength(ExprNode e, int index) { +private QlBuiltins::BigInt getArrayLength(ExprNode e, QlBuiltins::BigInt index) { exists(ArrayCreation arrCreation, ExprNode length | - hasChild(arrCreation, arrCreation.getLengthArgument(index), e, length) and + hasChild(arrCreation, arrCreation.getLengthArgument(any(int i | i.toBigInt() = index)), e, + length) and constantIntegerExpr(length, result) ) } -private int getArrayLengthRec(ExprNode arrCreation, int index) { - index = 0 and result = getArrayLength(arrCreation, 0) +private QlBuiltins::BigInt getArrayLengthRec(ExprNode arrCreation, QlBuiltins::BigInt index) { + index = 0.toBigInt() and result = getArrayLength(arrCreation, 0.toBigInt()) or - index > 0 and - result = getArrayLength(arrCreation, index) * getArrayLengthRec(arrCreation, index - 1) + index > 0.toBigInt() and + result = getArrayLength(arrCreation, index) * getArrayLengthRec(arrCreation, index - 1.toBigInt()) } -private predicate isArrayLengthAccess(ExprNode e, int length) { +private predicate isArrayLengthAccess(ExprNode e, QlBuiltins::BigInt length) { exists(PropertyAccess pa, ExprNode arrCreation | systemArrayLengthAccess(pa) and getArrayLengthRec(arrCreation, - arrCreation.getExpr().(ArrayCreation).getNumberOfLengthArguments() - 1) = length and + (arrCreation.getExpr().(ArrayCreation).getNumberOfLengthArguments() - 1).toBigInt()) = length and hasChild(pa, pa.getQualifier(), e, getAnExplicitDefinitionRead(arrCreation)) ) } @@ -61,5 +62,5 @@ class ConstantIntegerExpr extends ExprNode { ConstantIntegerExpr() { constantIntegerExpr(this, _) } /** Gets the integer value of this expression. */ - int getIntValue() { constantIntegerExpr(this, result) } + QlBuiltins::BigInt getIntValue() { constantIntegerExpr(this, result) } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll index 1be94669951f..50134d9fbbc2 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll @@ -33,33 +33,33 @@ private module Impl { } /** Holds if SSA definition `def` equals `e + delta`. */ - predicate ssaUpdateStep(ExplicitDefinition def, ExprNode e, int delta) { + predicate ssaUpdateStep(ExplicitDefinition def, ExprNode e, QlBuiltins::BigInt delta) { exists(ControlFlow::Node cfn | cfn = def.getControlFlowNode() | - e = cfn.(ExprNode::Assignment).getRValue() and delta = 0 + e = cfn.(ExprNode::Assignment).getRValue() and delta = 0.toBigInt() or - e = cfn.(ExprNode::PostIncrExpr).getOperand() and delta = 1 + e = cfn.(ExprNode::PostIncrExpr).getOperand() and delta = 1.toBigInt() or - e = cfn.(ExprNode::PreIncrExpr).getOperand() and delta = 1 + e = cfn.(ExprNode::PreIncrExpr).getOperand() and delta = 1.toBigInt() or - e = cfn.(ExprNode::PostDecrExpr).getOperand() and delta = -1 + e = cfn.(ExprNode::PostDecrExpr).getOperand() and delta = -1.toBigInt() or - e = cfn.(ExprNode::PreDecrExpr).getOperand() and delta = -1 + e = cfn.(ExprNode::PreDecrExpr).getOperand() and delta = -1.toBigInt() ) } /** Holds if `e1 + delta` equals `e2`. */ - predicate valueFlowStep(ExprNode e2, ExprNode e1, int delta) { - e2.(ExprNode::AssignExpr).getRValue() = e1 and delta = 0 + predicate valueFlowStep(ExprNode e2, ExprNode e1, QlBuiltins::BigInt delta) { + e2.(ExprNode::AssignExpr).getRValue() = e1 and delta = 0.toBigInt() or - e2.(ExprNode::UnaryPlusExpr).getOperand() = e1 and delta = 0 + e2.(ExprNode::UnaryPlusExpr).getOperand() = e1 and delta = 0.toBigInt() or - e2.(ExprNode::PostIncrExpr).getOperand() = e1 and delta = 0 + e2.(ExprNode::PostIncrExpr).getOperand() = e1 and delta = 0.toBigInt() or - e2.(ExprNode::PostDecrExpr).getOperand() = e1 and delta = 0 + e2.(ExprNode::PostDecrExpr).getOperand() = e1 and delta = 0.toBigInt() or - e2.(ExprNode::PreIncrExpr).getOperand() = e1 and delta = 1 + e2.(ExprNode::PreIncrExpr).getOperand() = e1 and delta = 1.toBigInt() or - e2.(ExprNode::PreDecrExpr).getOperand() = e1 and delta = -1 + e2.(ExprNode::PreDecrExpr).getOperand() = e1 and delta = -1.toBigInt() or exists(ConstantIntegerExpr x | e2.(ExprNode::AddExpr).getAnOperand() = e1 and @@ -77,7 +77,7 @@ private module Impl { // Conditional expressions with only one branch can happen either // because of pruning or because of Boolean splitting. In such cases // the conditional expression has the same value as the branch. - delta = 0 and + delta = 0.toBigInt() and e2 = any(ExprNode::ConditionalExpr ce | e1 = ce.getTrueExpr() and @@ -112,7 +112,7 @@ private module Impl { } private Guard eqFlowCondAbs( - Definition def, ExprNode e, int delta, boolean isEq, G::AbstractValue v + Definition def, ExprNode e, QlBuiltins::BigInt delta, boolean isEq, G::AbstractValue v ) { exists(boolean eqpolarity | result.isEquality(ssaRead(def, delta), e, eqpolarity) and @@ -131,7 +131,9 @@ private module Impl { * - `isEq = true` : `def == e + delta` * - `isEq = false` : `def != e + delta` */ - Guard eqFlowCond(Definition def, ExprNode e, int delta, boolean isEq, boolean testIsTrue) { + Guard eqFlowCond( + Definition def, ExprNode e, QlBuiltins::BigInt delta, boolean isEq, boolean testIsTrue + ) { exists(BooleanValue v | result = eqFlowCondAbs(def, e, delta, isEq, v) and testIsTrue = v.getValue() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll index 6f0067517f90..357fe190d8e6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll @@ -12,12 +12,12 @@ private import Sign /** Gets the sign of `e` if this can be directly determined. */ private Sign certainExprSign(Expr e) { - exists(int i | e.(ConstantIntegerExpr).getIntValue() = i | - i < 0 and result = TNeg() + exists(QlBuiltins::BigInt i | e.(ConstantIntegerExpr).getIntValue() = i | + i < 0.toBigInt() and result = TNeg() or - i = 0 and result = TZero() + i = 0.toBigInt() and result = TZero() or - i > 0 and result = TPos() + i > 0.toBigInt() and result = TPos() ) or not exists(e.(ConstantIntegerExpr).getIntValue()) and @@ -67,12 +67,12 @@ private predicate lowerBound(Expr lowerbound, SsaVariable v, SsaReadPosition pos | testIsTrue = true and comp.getLesserOperand() = lowerbound and - comp.getGreaterOperand() = ssaRead(v, 0) and + comp.getGreaterOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = true else isStrict = false) or testIsTrue = false and comp.getGreaterOperand() = lowerbound and - comp.getLesserOperand() = ssaRead(v, 0) and + comp.getLesserOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = false else isStrict = true) ) } @@ -89,12 +89,12 @@ private predicate upperBound(Expr upperbound, SsaVariable v, SsaReadPosition pos | testIsTrue = true and comp.getGreaterOperand() = upperbound and - comp.getLesserOperand() = ssaRead(v, 0) and + comp.getLesserOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = true else isStrict = false) or testIsTrue = false and comp.getLesserOperand() = upperbound and - comp.getGreaterOperand() = ssaRead(v, 0) and + comp.getGreaterOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = false else isStrict = true) ) } @@ -110,7 +110,7 @@ private predicate eqBound(Expr eqbound, SsaVariable v, SsaReadPosition pos, bool exists(Guard guard, boolean testIsTrue, boolean polarity | pos.hasReadOfVar(v) and guardControlsSsaRead(guard, pos, testIsTrue) and - guard.isEquality(eqbound, ssaRead(v, 0), polarity) and + guard.isEquality(eqbound, ssaRead(v, 0.toBigInt()), polarity) and isEq = polarity.booleanXor(testIsTrue).booleanNot() and not unknownSign(eqbound) ) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll index b26082b6250a..c31825f95083 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaUtils.qll @@ -26,10 +26,10 @@ ExprNode getAnExplicitDefinitionRead(ExprNode src) { /** * Gets an expression that equals `v - delta`. */ -ExprNode ssaRead(Definition v, int delta) { - exists(v.getAReadAtNode(result)) and delta = 0 +ExprNode ssaRead(Definition v, QlBuiltins::BigInt delta) { + exists(v.getAReadAtNode(result)) and delta = 0.toBigInt() or - exists(ExprNode::AddExpr add, int d1, ConstantIntegerExpr c | + exists(ExprNode::AddExpr add, QlBuiltins::BigInt d1, ConstantIntegerExpr c | result = add and delta = d1 - c.getIntValue() | @@ -38,22 +38,27 @@ ExprNode ssaRead(Definition v, int delta) { add.getRightOperand() = ssaRead(v, d1) and add.getLeftOperand() = c ) or - exists(ExprNode::SubExpr sub, int d1, ConstantIntegerExpr c | + exists(ExprNode::SubExpr sub, QlBuiltins::BigInt d1, ConstantIntegerExpr c | result = sub and sub.getLeftOperand() = ssaRead(v, d1) and sub.getRightOperand() = c and delta = d1 + c.getIntValue() ) or - v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PreIncrExpr) = result and delta = 0 + v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PreIncrExpr) = result and + delta = 0.toBigInt() or - v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PreDecrExpr) = result and delta = 0 + v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PreDecrExpr) = result and + delta = 0.toBigInt() or - v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PostIncrExpr) = result and delta = 1 // x++ === ++x - 1 + v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PostIncrExpr) = result and + delta = 1.toBigInt() // x++ === ++x - 1 or - v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PostDecrExpr) = result and delta = -1 // x-- === --x + 1 + v.(ExplicitDefinition).getControlFlowNode().(ExprNode::PostDecrExpr) = result and + delta = -1.toBigInt() // x-- === --x + 1 or - v.(ExplicitDefinition).getControlFlowNode().(ExprNode::Assignment) = result and delta = 0 + v.(ExplicitDefinition).getControlFlowNode().(ExprNode::Assignment) = result and + delta = 0.toBigInt() or result.(ExprNode::AssignExpr).getRValue() = ssaRead(v, delta) } diff --git a/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql index 02ffbc535ce8..184bfce9e236 100644 --- a/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql +++ b/csharp/ql/test/library-tests/dataflow/modulusanalysis/ModulusAnalysis.ql @@ -3,8 +3,8 @@ import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils import semmle.code.csharp.dataflow.ModulusAnalysis import semmle.code.csharp.dataflow.Bound -from ControlFlow::Nodes::ExprNode e, Bound b, int delta, int mod +from ControlFlow::Nodes::ExprNode e, Bound b, QlBuiltins::BigInt delta, QlBuiltins::BigInt mod where not e.getExpr().fromLibrary() and exprModulus(e, b, delta, mod) -select e, b.toString(), delta, mod +select e, b.toString(), delta.toString(), mod.toString() diff --git a/java/ql/lib/semmle/code/java/Constants.qll b/java/ql/lib/semmle/code/java/Constants.qll index 9e35a925be33..69bab0e9cc63 100644 --- a/java/ql/lib/semmle/code/java/Constants.qll +++ b/java/ql/lib/semmle/code/java/Constants.qll @@ -6,7 +6,7 @@ import java signature boolean getBoolValSig(Expr e); -signature int getIntValSig(Expr e); +signature QlBuiltins::BigInt getBigIntValSig(Expr e); /** * Given predicates defining boolean and integer constants, this module @@ -15,7 +15,7 @@ signature int getIntValSig(Expr e); * * The input and output predicates are expected to be mutually recursive. */ -module CalculateConstants { +module CalculateConstants { /** Gets the value of a constant boolean expression. */ boolean calculateBooleanValue(Expr e) { // No casts relevant to booleans. @@ -23,10 +23,10 @@ module CalculateConstants result = getBoolVal(e.(LogNotExpr).getExpr()).booleanNot() or // Handle binary expressions that have integer operands and a boolean result. - exists(BinaryExpr b, int left, int right | + exists(BinaryExpr b, QlBuiltins::BigInt left, QlBuiltins::BigInt right | b = e and - left = getIntVal(b.getLeftOperand()) and - right = getIntVal(b.getRightOperand()) + left = getBigIntVal(b.getLeftOperand()) and + right = getBigIntVal(b.getRightOperand()) | ( b instanceof LTExpr and @@ -97,33 +97,35 @@ module CalculateConstants ) } - /** Gets the value of a constant integer expression. */ - int calculateIntValue(Expr e) { - exists(IntegralType t | e.getType() = t | t.getName().toLowerCase() != "long") and + /** Gets the big int value of a constant integer expression. */ + QlBuiltins::BigInt calculateBigIntValue(Expr e) { + e.getType() instanceof IntegralType and ( - exists(CastingExpr cast, int val | cast = e and val = getIntVal(cast.getExpr()) | + exists(CastingExpr cast, QlBuiltins::BigInt val | + cast = e and val = getBigIntVal(cast.getExpr()) + | if cast.getType().hasName("byte") - then result = (val + 128).bitAnd(255) - 128 + then result = (val + 128.toBigInt()).bitAnd(255.toBigInt()) - 128.toBigInt() else if cast.getType().hasName("short") - then result = (val + 32768).bitAnd(65535) - 32768 + then result = (val + 32768.toBigInt()).bitAnd(65535.toBigInt()) - 32768.toBigInt() else if cast.getType().hasName("char") - then result = val.bitAnd(65535) + then result = val.bitAnd(65535.toBigInt()) else result = val ) or - result = getIntVal(e.(PlusExpr).getExpr()) + result = getBigIntVal(e.(PlusExpr).getExpr()) or - result = -getIntVal(e.(MinusExpr).getExpr()) + result = -getBigIntVal(e.(MinusExpr).getExpr()) or - result = getIntVal(e.(BitNotExpr).getExpr()).bitNot() + result = getBigIntVal(e.(BitNotExpr).getExpr()).bitNot() or // No `int` value for `LogNotExpr`. - exists(BinaryExpr b, int v1, int v2 | + exists(BinaryExpr b, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2 | b = e and - v1 = getIntVal(b.getLeftOperand()) and - v2 = getIntVal(b.getRightOperand()) + v1 = getBigIntVal(b.getLeftOperand()) and + v2 = getBigIntVal(b.getRightOperand()) | b instanceof MulExpr and result = v1 * v2 or @@ -135,11 +137,12 @@ module CalculateConstants or b instanceof SubExpr and result = v1 - v2 or - b instanceof LeftShiftExpr and result = v1.bitShiftLeft(v2) + b instanceof LeftShiftExpr and result = v1.bitShiftLeft(v2.toInt()) or - b instanceof RightShiftExpr and result = v1.bitShiftRightSigned(v2) + b instanceof RightShiftExpr and result = v1.bitShiftRightSigned(v2.toInt()) or - b instanceof UnsignedRightShiftExpr and result = v1.bitShiftRight(v2) + b instanceof UnsignedRightShiftExpr and + result = v1.toInt().bitShiftRight(v2.toInt()).toBigInt() // bitShiftRight not implemented on bigints (yet) or b instanceof AndBitwiseExpr and result = v1.bitAnd(v2) or @@ -154,12 +157,12 @@ module CalculateConstants exists(ConditionalExpr ce, boolean condition | ce = e and condition = getBoolVal(ce.getCondition()) and - result = getIntVal(ce.getBranchExpr(condition)) + result = getBigIntVal(ce.getBranchExpr(condition)) ) or // If a `Variable` is final, its value is its initializer, if it exists. exists(Variable v | e = v.getAnAccess() and v.isFinal() | - result = getIntVal(v.getInitializer()) + result = getBigIntVal(v.getInitializer()) ) ) } diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index 1862319e30bb..8cfc94040b1d 100644 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -249,25 +249,33 @@ class CompileTimeConstantExpr extends Expr { * - values of type `long`. */ cached - int getIntValue() { - exists(IntegralType t | this.getType() = t | t.getName().toLowerCase() != "long") and + int getIntValue() { result = this.getBigIntValue().toInt() } + + /** + * Gets the big integer value of this expression, where possible. + */ + cached + QlBuiltins::BigInt getBigIntValue() { + this.getType() instanceof IntegralType and ( - result = this.(IntegerLiteral).getIntValue() + result = this.(IntegerLiteral).getBigIntValue() or - result = this.(CharacterLiteral).getCodePointValue() + result = this.(CharacterLiteral).getCodePointValue().toBigInt() ) or - result = CalcCompileTimeConstants::calculateIntValue(this) + result = CalcCompileTimeConstants::calculateBigIntValue(this) or - result = this.(LiveLiteral).getValue().getIntValue() + result = this.(LiveLiteral).getValue().getBigIntValue() } } private boolean getBoolValue(Expr e) { result = e.(CompileTimeConstantExpr).getBooleanValue() } -private int getIntValue(Expr e) { result = e.(CompileTimeConstantExpr).getIntValue() } +private QlBuiltins::BigInt getBigIntValue(Expr e) { + result = e.(CompileTimeConstantExpr).getBigIntValue() +} -private module CalcCompileTimeConstants = CalculateConstants; +private module CalcCompileTimeConstants = CalculateConstants; /** An expression parent is an element that may have an expression as its child. */ class ExprParent extends @exprparent, Top { } @@ -590,6 +598,9 @@ class IntegerLiteral extends Literal, @integerliteral { /** Gets the int representation of this literal. */ int getIntValue() { result = this.getValue().toInt() } + /** Gets the big int representation of this literal. */ + QlBuiltins::BigInt getBigIntValue() { result = this.getValue().toBigInt() } + override string getAPrimaryQlClass() { result = "IntegerLiteral" } } diff --git a/java/ql/lib/semmle/code/java/controlflow/internal/GuardsLogic.qll b/java/ql/lib/semmle/code/java/controlflow/internal/GuardsLogic.qll index 9fed7516ba31..dd827e1bf15e 100644 --- a/java/ql/lib/semmle/code/java/controlflow/internal/GuardsLogic.qll +++ b/java/ql/lib/semmle/code/java/controlflow/internal/GuardsLogic.qll @@ -386,9 +386,9 @@ private predicate guardImpliesNotEqual2( ( guard = directNullGuard(v0, branch, false) and val = TAbsValNull() or - exists(int k | + exists(QlBuiltins::BigInt k | guard = integerGuard(v0.getAUse(), branch, k, false) and - val = TAbsValInt(k) + val = TAbsValInt(k.toInt()) ) ) and (v = v0 or equalVarsInBlock(guard.getBasicBlock(), v0, v)) diff --git a/java/ql/lib/semmle/code/java/dataflow/Bound.qll b/java/ql/lib/semmle/code/java/dataflow/Bound.qll index 08826b7ae8f1..a6b4e83b917c 100644 --- a/java/ql/lib/semmle/code/java/dataflow/Bound.qll +++ b/java/ql/lib/semmle/code/java/dataflow/Bound.qll @@ -20,10 +20,10 @@ abstract class Bound extends TBound { abstract string toString(); /** Gets an expression that equals this bound plus `delta`. */ - abstract Expr getExpr(int delta); + abstract Expr getExpr(QlBuiltins::BigInt delta); /** Gets an expression that equals this bound. */ - Expr getExpr() { result = this.getExpr(0) } + Expr getExpr() { result = this.getExpr(0.toBigInt()) } /** Gets the location of this bound. */ abstract Location getLocation(); @@ -36,7 +36,9 @@ abstract class Bound extends TBound { class ZeroBound extends Bound, TBoundZero { override string toString() { result = "0" } - override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta } + override Expr getExpr(QlBuiltins::BigInt delta) { + result.(ConstantIntegerExpr).getIntValue() = delta + } override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) } } @@ -50,7 +52,9 @@ class SsaBound extends Bound, TBoundSsa { override string toString() { result = this.getSsa().toString() } - override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 } + override Expr getExpr(QlBuiltins::BigInt delta) { + result = this.getSsa().getAUse() and delta = 0.toBigInt() + } override Location getLocation() { result = this.getSsa().getLocation() } } @@ -62,7 +66,9 @@ class SsaBound extends Bound, TBoundSsa { class ExprBound extends Bound, TBoundExpr { override string toString() { result = this.getExpr().toString() } - override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 } + override Expr getExpr(QlBuiltins::BigInt delta) { + this = TBoundExpr(result) and delta = 0.toBigInt() + } override Location getLocation() { result = this.getExpr().getLocation() } } diff --git a/java/ql/lib/semmle/code/java/dataflow/IntegerGuards.qll b/java/ql/lib/semmle/code/java/dataflow/IntegerGuards.qll index 58d77b649788..f0041cc5fa38 100644 --- a/java/ql/lib/semmle/code/java/dataflow/IntegerGuards.qll +++ b/java/ql/lib/semmle/code/java/dataflow/IntegerGuards.qll @@ -8,7 +8,7 @@ private import RangeUtils private import RangeAnalysis /** Gets an expression that might have the value `i`. */ -private Expr exprWithIntValue(int i) { +private Expr exprWithIntValue(QlBuiltins::BigInt i) { result.(ConstantIntegerExpr).getIntValue() = i or result.(ChooseExpr).getAResultExpr() = exprWithIntValue(i) } @@ -21,14 +21,14 @@ class IntComparableExpr extends Expr { IntComparableExpr() { this instanceof VarRead or this instanceof MethodCall } /** Gets an integer that is directly assigned to the expression in case of a variable; or zero. */ - int relevantInt() { + QlBuiltins::BigInt relevantInt() { exists(SsaExplicitUpdate ssa, SsaSourceVariable v | this = v.getAnAccess() and ssa.getSourceVariable() = v and ssa.getDefiningExpr().(VariableAssign).getSource() = exprWithIntValue(result) ) or - result = 0 + result = 0.toBigInt() } } @@ -41,7 +41,7 @@ class IntComparableExpr extends Expr { * is true, and different from `k` if `is_k` is false. */ pragma[nomagic] -Expr integerGuard(IntComparableExpr e, boolean branch, int k, boolean is_k) { +Expr integerGuard(IntComparableExpr e, boolean branch, QlBuiltins::BigInt k, boolean is_k) { exists(EqualityTest eqtest, boolean polarity | eqtest = result and eqtest.hasOperands(e, any(ConstantIntegerExpr c | c.getIntValue() = k)) and @@ -53,7 +53,7 @@ Expr integerGuard(IntComparableExpr e, boolean branch, int k, boolean is_k) { ) ) or - exists(EqualityTest eqtest, int val, Expr c, boolean upper | + exists(EqualityTest eqtest, QlBuiltins::BigInt val, Expr c, boolean upper | k = e.relevantInt() and eqtest = result and eqtest.hasOperands(e, c) and @@ -67,7 +67,7 @@ Expr integerGuard(IntComparableExpr e, boolean branch, int k, boolean is_k) { branch = eqtest.polarity() ) or - exists(ComparisonExpr comp, Expr c, int val, boolean upper | + exists(ComparisonExpr comp, Expr c, QlBuiltins::BigInt val, boolean upper | k = e.relevantInt() and comp = result and comp.hasOperands(e, c) and @@ -132,8 +132,8 @@ Expr integerGuard(IntComparableExpr e, boolean branch, int k, boolean is_k) { * If `branch_with_lower_bound_k` is true then `result` is equivalent to `k <= x` * and if it is false then `result` is equivalent to `k > x`. */ -Expr intBoundGuard(VarRead x, boolean branch_with_lower_bound_k, int k) { - exists(ComparisonExpr comp, ConstantIntegerExpr c, int val | +Expr intBoundGuard(VarRead x, boolean branch_with_lower_bound_k, QlBuiltins::BigInt k) { + exists(ComparisonExpr comp, ConstantIntegerExpr c, QlBuiltins::BigInt val | comp = result and comp.hasOperands(x, c) and c.getIntValue() = val and @@ -143,7 +143,7 @@ Expr intBoundGuard(VarRead x, boolean branch_with_lower_bound_k, int k) { comp.getLesserOperand() = c and comp.isStrict() and branch_with_lower_bound_k = true and - val + 1 = k + val + 1.toBigInt() = k or // c <= x comp.getLesserOperand() = c and @@ -161,6 +161,6 @@ Expr intBoundGuard(VarRead x, boolean branch_with_lower_bound_k, int k) { comp.getGreaterOperand() = c and not comp.isStrict() and branch_with_lower_bound_k = false and - val + 1 = k + val + 1.toBigInt() = k ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll b/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll index 5b2a39ad6c9e..acd820d62c8f 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll @@ -11,7 +11,9 @@ private import internal.rangeanalysis.SsaReadPositionCommon /** * Holds if `e + delta` equals `v` at `pos`. */ -private predicate valueFlowStepSsa(SsaVariable v, SsaReadPosition pos, Expr e, int delta) { +private predicate valueFlowStepSsa( + SsaVariable v, SsaReadPosition pos, Expr e, QlBuiltins::BigInt delta +) { ssaUpdateStep(v, e, delta) and pos.hasReadOfVar(v) or exists(Guard guard, boolean testIsTrue | @@ -47,17 +49,17 @@ private predicate nonConstSubtraction(Expr sub, Expr larg, Expr rarg) { } /** Gets an expression that is the remainder modulo `mod` of `arg`. */ -private Expr modExpr(Expr arg, int mod) { +private Expr modExpr(Expr arg, QlBuiltins::BigInt mod) { exists(RemExpr rem | result = rem and arg = rem.getLeftOperand() and rem.getRightOperand().(ConstantIntegerExpr).getIntValue() = mod and - mod >= 2 + mod >= 2.toBigInt() ) or exists(ConstantIntegerExpr c | - mod = 2.pow([1 .. 30]) and - c.getIntValue() = mod - 1 and + mod = 2.toBigInt().pow([1 .. 30]) and + c.getIntValue() = mod - 1.toBigInt() and result.(BitwiseAndExpr).hasOperands(arg, c) ) } @@ -66,8 +68,10 @@ private Expr modExpr(Expr arg, int mod) { * Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on * its `testIsTrue` branch. */ -private Guard moduloCheck(SsaVariable v, int val, int mod, boolean testIsTrue) { - exists(Expr rem, ConstantIntegerExpr c, int r, boolean polarity | +private Guard moduloCheck( + SsaVariable v, QlBuiltins::BigInt val, QlBuiltins::BigInt mod, boolean testIsTrue +) { + exists(Expr rem, ConstantIntegerExpr c, QlBuiltins::BigInt r, boolean polarity | result.isEquality(rem, c, polarity) and c.getIntValue() = r and rem = modExpr(v.getAUse(), mod) and @@ -75,9 +79,9 @@ private Guard moduloCheck(SsaVariable v, int val, int mod, boolean testIsTrue) { testIsTrue = polarity and val = r or testIsTrue = polarity.booleanNot() and - mod = 2 and - val = 1 - r and - (r = 0 or r = 1) + mod = 2.toBigInt() and + val = 1.toBigInt() - r and + (r = 0.toBigInt() or r = 1.toBigInt()) ) ) } @@ -85,7 +89,9 @@ private Guard moduloCheck(SsaVariable v, int val, int mod, boolean testIsTrue) { /** * Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`. */ -private predicate moduloGuardedRead(SsaVariable v, SsaReadPosition pos, int val, int mod) { +private predicate moduloGuardedRead( + SsaVariable v, SsaReadPosition pos, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(Guard guard, boolean testIsTrue | pos.hasReadOfVar(v) and guard = moduloCheck(v, val, mod, testIsTrue) and @@ -101,13 +107,14 @@ private predicate andmaskFactor(int mask, int factor) { } /** Holds if `e` is evenly divisible by `factor`. */ -private predicate evenlyDivisibleExpr(Expr e, int factor) { - exists(ConstantIntegerExpr c, int k | k = c.getIntValue() | - e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2 +private predicate evenlyDivisibleExpr(Expr e, QlBuiltins::BigInt factor) { + exists(ConstantIntegerExpr c, QlBuiltins::BigInt k | k = c.getIntValue() | + e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2.toBigInt() or - e.(LeftShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0 + e.(LeftShiftExpr).getRhs() = c and factor = 2.toBigInt().pow(k.toInt()) and k > 0.toBigInt() or - e.(BitwiseAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f)) + e.(BitwiseAndExpr).getAnOperand() = c and + factor = max(int f | andmaskFactor(k.toInt(), f)).toBigInt() ) } @@ -118,31 +125,33 @@ private predicate evenlyDivisibleExpr(Expr e, int factor) { * the range `[0 .. mod-1]`. */ bindingset[val, mod] -private int remainder(int val, int mod) { - mod = 0 and result = val +private QlBuiltins::BigInt remainder(QlBuiltins::BigInt val, QlBuiltins::BigInt mod) { + mod = 0.toBigInt() and result = val or - mod > 1 and result = ((val % mod) + mod) % mod + mod > 1.toBigInt() and result = ((val % mod) + mod) % mod } /** * Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`. */ private predicate phiSelfModulus( - SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, int mod + SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, QlBuiltins::BigInt mod ) { - exists(SsaBound phibound, int v, int m | + exists(SsaBound phibound, QlBuiltins::BigInt v, QlBuiltins::BigInt m | edge.phiInput(phi, inp) and phibound.getSsa() = phi and ssaModulus(inp, edge, phibound, v, m) and mod = m.gcd(v) and - mod != 1 + mod != 1.toBigInt() ) } /** * Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`. */ -private predicate phiModulusInit(SsaPhiNode phi, Bound b, int val, int mod) { +private predicate phiModulusInit( + SsaPhiNode phi, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(SsaVariable inp, SsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) and ssaModulus(inp, edge, b, val, mod) @@ -152,22 +161,26 @@ private predicate phiModulusInit(SsaPhiNode phi, Bound b, int val, int mod) { /** * Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`. */ -private predicate phiModulusRankStep(SsaPhiNode phi, Bound b, int val, int mod, int rix) { +private predicate phiModulusRankStep( + SsaPhiNode phi, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod, int rix +) { rix = 0 and phiModulusInit(phi, b, val, mod) or - exists(SsaVariable inp, SsaReadPositionPhiInputEdge edge, int v1, int m1 | - mod != 1 and + exists( + SsaVariable inp, SsaReadPositionPhiInputEdge edge, QlBuiltins::BigInt v1, QlBuiltins::BigInt m1 + | + mod != 1.toBigInt() and val = remainder(v1, mod) | - exists(int v2, int m2 | + exists(QlBuiltins::BigInt v2, QlBuiltins::BigInt m2 | rankedPhiInput(phi, inp, edge, rix) and phiModulusRankStep(phi, b, v1, m1, rix - 1) and ssaModulus(inp, edge, b, v2, m2) and mod = m1.gcd(m2).gcd(v1 - v2) ) or - exists(int m2 | + exists(QlBuiltins::BigInt m2 | rankedPhiInput(phi, inp, edge, rix) and phiModulusRankStep(phi, b, v1, m1, rix - 1) and phiSelfModulus(phi, inp, edge, m2) and @@ -179,7 +192,7 @@ private predicate phiModulusRankStep(SsaPhiNode phi, Bound b, int val, int mod, /** * Holds if `phi` is equal to `b + val` modulo `mod`. */ -private predicate phiModulus(SsaPhiNode phi, Bound b, int val, int mod) { +private predicate phiModulus(SsaPhiNode phi, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod) { exists(int r | maxPhiInputRank(phi, r) and phiModulusRankStep(phi, b, val, mod, r) @@ -189,12 +202,14 @@ private predicate phiModulus(SsaPhiNode phi, Bound b, int val, int mod) { /** * Holds if `v` at `pos` is equal to `b + val` modulo `mod`. */ -private predicate ssaModulus(SsaVariable v, SsaReadPosition pos, Bound b, int val, int mod) { +private predicate ssaModulus( + SsaVariable v, SsaReadPosition pos, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { phiModulus(v, b, val, mod) and pos.hasReadOfVar(v) or - b.(SsaBound).getSsa() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0 + b.(SsaBound).getSsa() = v and pos.hasReadOfVar(v) and val = 0.toBigInt() and mod = 0.toBigInt() or - exists(Expr e, int val0, int delta | + exists(Expr e, QlBuiltins::BigInt val0, QlBuiltins::BigInt delta | exprModulus(e, b, val0, mod) and valueFlowStepSsa(v, pos, e, delta) and val = remainder(val0 + delta, mod) @@ -211,10 +226,10 @@ private predicate ssaModulus(SsaVariable v, SsaReadPosition pos, Bound b, int va * - `mod > 1`: `val` lies within the range `[0 .. mod-1]`. */ cached -predicate exprModulus(Expr e, Bound b, int val, int mod) { - e = b.getExpr(val) and mod = 0 +predicate exprModulus(Expr e, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod) { + e = b.getExpr(val) and mod = 0.toBigInt() or - evenlyDivisibleExpr(e, mod) and val = 0 and b instanceof ZeroBound + evenlyDivisibleExpr(e, mod) and val = 0.toBigInt() and b instanceof ZeroBound or exists(SsaVariable v, SsaReadPositionBlock bb | ssaModulus(v, bb, b, val, mod) and @@ -222,26 +237,32 @@ predicate exprModulus(Expr e, Bound b, int val, int mod) { getABasicBlockExpr(bb.getBlock()) = e ) or - exists(Expr mid, int val0, int delta | + exists(Expr mid, QlBuiltins::BigInt val0, QlBuiltins::BigInt delta | exprModulus(mid, b, val0, mod) and valueFlowStep(e, mid, delta) and val = remainder(val0 + delta, mod) ) or - exists(ConditionalExpr cond, int v1, int v2, int m1, int m2 | + exists( + ConditionalExpr cond, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt m1, + QlBuiltins::BigInt m2 + | cond = e and condExprBranchModulus(cond, true, b, v1, m1) and condExprBranchModulus(cond, false, b, v2, m2) and mod = m1.gcd(m2).gcd(v1 - v2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1, mod) ) or - exists(Bound b1, Bound b2, int v1, int v2, int m1, int m2 | + exists( + Bound b1, Bound b2, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt m1, + QlBuiltins::BigInt m2 + | addModulus(e, true, b1, v1, m1) and addModulus(e, false, b2, v2, m2) and mod = m1.gcd(m2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1 + v2, mod) | b = b1 and b2 instanceof ZeroBound @@ -249,22 +270,26 @@ predicate exprModulus(Expr e, Bound b, int val, int mod) { b = b2 and b1 instanceof ZeroBound ) or - exists(int v1, int v2, int m1, int m2 | + exists( + QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt m1, QlBuiltins::BigInt m2 + | subModulus(e, true, b, v1, m1) and subModulus(e, false, any(ZeroBound zb), v2, m2) and mod = m1.gcd(m2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1 - v2, mod) ) } private predicate condExprBranchModulus( - ConditionalExpr cond, boolean branch, Bound b, int val, int mod + ConditionalExpr cond, boolean branch, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod ) { exprModulus(cond.getBranchExpr(branch), b, val, mod) } -private predicate addModulus(Expr add, boolean isLeft, Bound b, int val, int mod) { +private predicate addModulus( + Expr add, boolean isLeft, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(Expr larg, Expr rarg | nonConstAddition(add, larg, rarg) | exprModulus(larg, b, val, mod) and isLeft = true or @@ -272,7 +297,9 @@ private predicate addModulus(Expr add, boolean isLeft, Bound b, int val, int mod ) } -private predicate subModulus(Expr sub, boolean isLeft, Bound b, int val, int mod) { +private predicate subModulus( + Expr sub, boolean isLeft, Bound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod +) { exists(Expr larg, Expr rarg | nonConstSubtraction(sub, larg, rarg) | exprModulus(larg, b, val, mod) and isLeft = true or diff --git a/java/ql/lib/semmle/code/java/dataflow/Nullness.qll b/java/ql/lib/semmle/code/java/dataflow/Nullness.qll index fb2fc668cf3a..1e7c0cb96c8e 100644 --- a/java/ql/lib/semmle/code/java/dataflow/Nullness.qll +++ b/java/ql/lib/semmle/code/java/dataflow/Nullness.qll @@ -236,7 +236,7 @@ private Expr nonEmptyExpr() { // ...or it is guarded by a condition proving its length to be non-zero. exists(ConditionBlock cond, boolean branch, FieldAccess length | cond.controls(result.getBasicBlock(), branch) and - cond.getCondition() = integerGuard(length, branch, 0, false) and + cond.getCondition() = integerGuard(length, branch, 0.toBigInt(), false) and length.getField().hasName("length") and length.getQualifier() = v.getAUse() ) @@ -266,7 +266,7 @@ private Expr nonEmptyExpr() { or // ...or a check on its `size`. exists(MethodCall size | - c = integerGuard(size, branch, 0, false) and + c = integerGuard(size, branch, 0.toBigInt(), false) and size.getMethod().hasName("size") and size.getQualifier() = v.getAUse() ) @@ -485,7 +485,10 @@ private predicate correlatedConditions( inverted = branch1.booleanXor(branch2) ) or - exists(SsaVariable v, VarRead rv1, VarRead rv2, int k, boolean branch1, boolean branch2 | + exists( + SsaVariable v, VarRead rv1, VarRead rv2, QlBuiltins::BigInt k, boolean branch1, + boolean branch2 + | rv1 = v.getAUse() and rv2 = v.getAUse() and cond1.getCondition() = integerGuard(rv1, branch1, k, true) and @@ -495,7 +498,7 @@ private predicate correlatedConditions( inverted = branch1.booleanXor(branch2) ) or - exists(SsaVariable v, int k, boolean branch1, boolean branch2 | + exists(SsaVariable v, QlBuiltins::BigInt k, boolean branch1, boolean branch2 | cond1.getCondition() = intBoundGuard(v.getAUse(), branch1, k) and cond2.getCondition() = intBoundGuard(v.getAUse(), branch2, k) and inverted = branch1.booleanXor(branch2) @@ -630,19 +633,19 @@ private Expr trackingVarGuard( ) ) or - exists(int k | + exists(QlBuiltins::BigInt k | init.(ConstantIntegerExpr).getIntValue() = k and kind = TrackVarKindInt() | result = integerGuard(trackvar.getAnAccess(), branch, k, isA) or - exists(int k2 | + exists(QlBuiltins::BigInt k2 | result = integerGuard(trackvar.getAnAccess(), branch.booleanNot(), k2, true) and isA = false and k2 != k ) or - exists(int bound, boolean branch_with_lower_bound | + exists(QlBuiltins::BigInt bound, boolean branch_with_lower_bound | result = intBoundGuard(trackvar.getAnAccess(), branch_with_lower_bound, bound) and isA = false | diff --git a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll index e0055d53f08d..bbca878c821e 100644 --- a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll +++ b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll @@ -285,40 +285,21 @@ module Modulus implements ModulusAnalysisSig { class ModBound = Bound; private import codeql.rangeanalysis.ModulusAnalysis as Mod - import Mod::ModulusAnalysis + import Mod::ModulusAnalysis } -module IntDelta implements DeltaSig { - class Delta = int; - - bindingset[d] - bindingset[result] - float toFloat(Delta d) { result = d } - - bindingset[d] - bindingset[result] - int toInt(Delta d) { result = d } - - bindingset[n] - bindingset[result] - Delta fromInt(int n) { result = n } - - bindingset[f] - Delta fromFloat(float f) { result = f } -} - -module JavaLangImpl implements LangSig { +module JavaLangImpl implements LangSig { /** * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`). */ - predicate hasConstantBound(Sem::Expr e, int bound, boolean upper) { + predicate hasConstantBound(Sem::Expr e, QlBuiltins::BigInt bound, boolean upper) { ( e.(MethodCall).getMethod() instanceof StringLengthMethod or e.(MethodCall).getMethod() instanceof CollectionSizeMethod or e.(MethodCall).getMethod() instanceof MapSizeMethod or e.(FieldRead).getField() instanceof ArrayLengthField ) and - bound = 0 and + bound = 0.toBigInt() and upper = false or exists(Method read | @@ -327,25 +308,27 @@ module JavaLangImpl implements LangSig { read.hasName("read") and read.getNumberOfParameters() = 0 | - upper = true and bound = 255 + upper = true and bound = 255.toBigInt() or - upper = false and bound = -1 + upper = false and bound = -1.toBigInt() ) } /** * Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`). */ - predicate additionalBoundFlowStep(Sem::Expr e2, Sem::Expr e1, int delta, boolean upper) { + predicate additionalBoundFlowStep( + Sem::Expr e2, Sem::Expr e1, QlBuiltins::BigInt delta, boolean upper + ) { exists(RandomDataSource rds | e2 = rds.getOutput() and ( e1 = rds.getUpperBoundExpr() and - delta = -1 and + delta = -1.toBigInt() and upper = true or e1 = rds.getLowerBoundExpr() and - delta = 0 and + delta = 0.toBigInt() and upper = false ) ) @@ -360,7 +343,7 @@ module JavaLangImpl implements LangSig { ) and m.getDeclaringType().hasQualifiedName("java.lang", "Math") and e1 = ma.getAnArgument() and - delta = 0 + delta = 0.toBigInt() ) } @@ -369,7 +352,7 @@ module JavaLangImpl implements LangSig { predicate javaCompatibility() { any() } } -module Bounds implements BoundSig { +module Bounds implements BoundSig { class SemBound = Bound; class SemZeroBound = ZeroBound; @@ -379,14 +362,13 @@ module Bounds implements BoundSig { } } -module Overflow implements OverflowSig { +module Overflow implements OverflowSig { predicate semExprDoesNotOverflow(boolean positively, Sem::Expr expr) { positively = [true, false] and exists(expr) } } -module Range = - RangeStage; +module Range = RangeStage; predicate bounded = Range::semBounded/5; diff --git a/java/ql/lib/semmle/code/java/dataflow/RangeUtils.qll b/java/ql/lib/semmle/code/java/dataflow/RangeUtils.qll index be7f73fe7668..48862608fb8d 100644 --- a/java/ql/lib/semmle/code/java/dataflow/RangeUtils.qll +++ b/java/ql/lib/semmle/code/java/dataflow/RangeUtils.qll @@ -9,7 +9,7 @@ private import semmle.code.java.Constants private import semmle.code.java.dataflow.RangeAnalysis private import codeql.rangeanalysis.internal.RangeUtils -private module U = MakeUtils; +private module U = MakeUtils; private predicate backEdge = U::backEdge/3; @@ -83,8 +83,8 @@ private predicate arrayLengthDef(FieldRead arrlen, ArrayCreationExpr def) { /** An expression that always has the same integer value. */ pragma[nomagic] -private predicate constantIntegerExpr(Expr e, int val) { - e.(CompileTimeConstantExpr).getIntValue() = val +private predicate constantIntegerExpr(Expr e, QlBuiltins::BigInt val) { + e.(CompileTimeConstantExpr).getBigIntValue() = val or exists(SsaExplicitUpdate v, Expr src | e = v.getAUse() and @@ -94,18 +94,18 @@ private predicate constantIntegerExpr(Expr e, int val) { or exists(ArrayCreationExpr a | arrayLengthDef(e, a) and - a.getFirstDimensionSize() = val + a.getFirstDimensionSize().toBigInt() = val ) or exists(Field a, FieldRead arrlen | a.isFinal() and - a.getInitializer().(ArrayCreationExpr).getFirstDimensionSize() = val and + a.getInitializer().(ArrayCreationExpr).getFirstDimensionSize().toBigInt() = val and arrlen.getField() instanceof ArrayLengthField and arrlen.getQualifier() = a.getAnAccess() and e = arrlen ) or - CalcConstants::calculateIntValue(e) = val + CalcConstants::calculateBigIntValue(e) = val } pragma[nomagic] @@ -134,16 +134,16 @@ private predicate constantStringExpr(Expr e, string val) { private boolean getBoolValue(Expr e) { constantBooleanExpr(e, result) } -private int getIntValue(Expr e) { constantIntegerExpr(e, result) } +private QlBuiltins::BigInt getBigIntValue(Expr e) { constantIntegerExpr(e, result) } -private module CalcConstants = CalculateConstants; +private module CalcConstants = CalculateConstants; /** An expression that always has the same integer value. */ class ConstantIntegerExpr extends Expr { ConstantIntegerExpr() { constantIntegerExpr(this, _) } /** Gets the integer value of this expression. */ - int getIntValue() { constantIntegerExpr(this, result) } + QlBuiltins::BigInt getIntValue() { constantIntegerExpr(this, result) } } /** An expression that always has the same boolean value. */ @@ -165,10 +165,10 @@ class ConstantStringExpr extends Expr { /** * Holds if `e1 + delta` equals `e2`. */ -predicate additionalValueFlowStep(Expr e2, Expr e1, int delta) { +predicate additionalValueFlowStep(Expr e2, Expr e1, QlBuiltins::BigInt delta) { exists(ArrayCreationExpr a | arrayLengthDef(e2, a) and a.getDimension(0) = e1 and - delta = 0 + delta = 0.toBigInt() ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll index 6f0067517f90..357fe190d8e6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll @@ -12,12 +12,12 @@ private import Sign /** Gets the sign of `e` if this can be directly determined. */ private Sign certainExprSign(Expr e) { - exists(int i | e.(ConstantIntegerExpr).getIntValue() = i | - i < 0 and result = TNeg() + exists(QlBuiltins::BigInt i | e.(ConstantIntegerExpr).getIntValue() = i | + i < 0.toBigInt() and result = TNeg() or - i = 0 and result = TZero() + i = 0.toBigInt() and result = TZero() or - i > 0 and result = TPos() + i > 0.toBigInt() and result = TPos() ) or not exists(e.(ConstantIntegerExpr).getIntValue()) and @@ -67,12 +67,12 @@ private predicate lowerBound(Expr lowerbound, SsaVariable v, SsaReadPosition pos | testIsTrue = true and comp.getLesserOperand() = lowerbound and - comp.getGreaterOperand() = ssaRead(v, 0) and + comp.getGreaterOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = true else isStrict = false) or testIsTrue = false and comp.getGreaterOperand() = lowerbound and - comp.getLesserOperand() = ssaRead(v, 0) and + comp.getLesserOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = false else isStrict = true) ) } @@ -89,12 +89,12 @@ private predicate upperBound(Expr upperbound, SsaVariable v, SsaReadPosition pos | testIsTrue = true and comp.getGreaterOperand() = upperbound and - comp.getLesserOperand() = ssaRead(v, 0) and + comp.getLesserOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = true else isStrict = false) or testIsTrue = false and comp.getLesserOperand() = upperbound and - comp.getGreaterOperand() = ssaRead(v, 0) and + comp.getGreaterOperand() = ssaRead(v, 0.toBigInt()) and (if comp.isStrict() then isStrict = false else isStrict = true) ) } @@ -110,7 +110,7 @@ private predicate eqBound(Expr eqbound, SsaVariable v, SsaReadPosition pos, bool exists(Guard guard, boolean testIsTrue, boolean polarity | pos.hasReadOfVar(v) and guardControlsSsaRead(guard, pos, testIsTrue) and - guard.isEquality(eqbound, ssaRead(v, 0), polarity) and + guard.isEquality(eqbound, ssaRead(v, 0.toBigInt()), polarity) and isEq = polarity.booleanXor(testIsTrue).booleanNot() and not unknownSign(eqbound) ) diff --git a/java/ql/lib/semmle/code/java/security/ArithmeticCommon.qll b/java/ql/lib/semmle/code/java/security/ArithmeticCommon.qll index 785dce3da7ed..e86a9289d099 100644 --- a/java/ql/lib/semmle/code/java/security/ArithmeticCommon.qll +++ b/java/ql/lib/semmle/code/java/security/ArithmeticCommon.qll @@ -21,14 +21,14 @@ predicate narrowerThanOrEqualTo(ArithExpr exp, NumType numType) { private Guard sizeGuard(SsaVariable v, boolean branch, boolean upper) { exists(ComparisonExpr comp | comp = result | - comp.getLesserOperand() = ssaRead(v, 0) and + comp.getLesserOperand() = ssaRead(v, 0.toBigInt()) and ( branch = true and upper = true or branch = false and upper = false ) or - comp.getGreaterOperand() = ssaRead(v, 0) and + comp.getGreaterOperand() = ssaRead(v, 0.toBigInt()) and ( branch = true and upper = false or @@ -37,7 +37,7 @@ private Guard sizeGuard(SsaVariable v, boolean branch, boolean upper) { or exists(MethodCall ma | ma.getMethod() instanceof MethodAbs and - ma.getArgument(0) = ssaRead(v, 0) and + ma.getArgument(0) = ssaRead(v, 0.toBigInt()) and ( comp.getLesserOperand() = ma and branch = true or @@ -48,7 +48,7 @@ private Guard sizeGuard(SsaVariable v, boolean branch, boolean upper) { or // overflow test exists(AddExpr add, VarRead use, Expr pos | - use = ssaRead(v, 0) and + use = ssaRead(v, 0.toBigInt()) and add.hasOperands(use, pos) and positive(use) and positive(pos) and @@ -64,12 +64,12 @@ private Guard sizeGuard(SsaVariable v, boolean branch, boolean upper) { ) ) or - result.isEquality(ssaRead(v, 0), _, branch) and + result.isEquality(ssaRead(v, 0.toBigInt()), _, branch) and (upper = true or upper = false) or exists(MethodCall call, Method m, int ix | call = result and - call.getArgument(ix) = ssaRead(v, 0) and + call.getArgument(ix) = ssaRead(v, 0.toBigInt()) and call.getMethod().getSourceDeclaration() = m and m = customSizeGuard(ix, branch, upper) ) diff --git a/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll b/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll index b6bd505c38b8..e7e0b2013e77 100644 --- a/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll +++ b/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll @@ -73,10 +73,10 @@ private class SmallType extends Type { } private predicate smallExpr(Expr e) { - exists(int low, int high | + exists(QlBuiltins::BigInt low, QlBuiltins::BigInt high | bounded(e, any(ZeroBound zb), low, false, _) and bounded(e, any(ZeroBound zb), high, true, _) and - high - low < 256 + high - low < 256.toBigInt() ) } diff --git a/java/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql b/java/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql index 31a1d8a20a13..7f092d258084 100644 --- a/java/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql +++ b/java/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql @@ -21,10 +21,10 @@ import semmle.code.java.dataflow.RangeAnalysis import semmle.code.java.Conversions /** Gets an upper bound on the absolute value of `e`. */ -float exprBound(Expr e) { - result = e.(ConstantIntegerExpr).getIntValue().(float).abs() +QlBuiltins::BigInt exprBound(Expr e) { + result = e.(ConstantIntegerExpr).getIntValue().abs() or - exists(float lower, float upper | + exists(QlBuiltins::BigInt lower, QlBuiltins::BigInt upper | bounded(e, any(ZeroBound zb), lower, false, _) and bounded(e, any(ZeroBound zb), upper, true, _) and result = upper.abs().maximum(lower.abs()) @@ -33,11 +33,13 @@ float exprBound(Expr e) { /** A multiplication that does not overflow. */ predicate small(MulExpr e) { - exists(NumType t, float lhs, float rhs, float res | t = e.getType() | + exists(NumType t, QlBuiltins::BigInt lhs, QlBuiltins::BigInt rhs, QlBuiltins::BigInt res | + t = e.getType() + | lhs = exprBound(e.getLeftOperand()) and rhs = exprBound(e.getRightOperand()) and lhs * rhs = res and - res <= t.getOrdPrimitiveType().getMaxValue() + res <= t.getOrdPrimitiveType().getMaxValue().toString().toBigInt() ) } diff --git a/java/ql/src/Likely Bugs/Collections/ArrayIndexOutOfBounds.ql b/java/ql/src/Likely Bugs/Collections/ArrayIndexOutOfBounds.ql index c94801189b3f..89609d313874 100644 --- a/java/ql/src/Likely Bugs/Collections/ArrayIndexOutOfBounds.ql +++ b/java/ql/src/Likely Bugs/Collections/ArrayIndexOutOfBounds.ql @@ -21,7 +21,7 @@ import semmle.code.java.dataflow.RangeAnalysis * Holds if the index expression of `aa` is less than or equal to the array length plus `k`. */ predicate boundedArrayAccess(ArrayAccess aa, int k) { - exists(SsaVariable arr, Expr index, Bound b, int delta | + exists(SsaVariable arr, Expr index, Bound b, QlBuiltins::BigInt delta | aa.getIndexExpr() = index and aa.getArray() = arr.getAUse() and bounded(index, b, delta, true, _) @@ -30,28 +30,28 @@ predicate boundedArrayAccess(ArrayAccess aa, int k) { len.getField() instanceof ArrayLengthField and len.getQualifier() = arr.getAUse() and b.getExpr() = len and - k = delta + k = delta.toInt() ) or exists(ArrayCreationExpr arraycreation | arraycreation = getArrayDef(arr) | - k = delta and + k = delta.toInt() and arraycreation.getDimension(0) = b.getExpr() or exists(int arrlen | arraycreation.getFirstDimensionSize() = arrlen and b instanceof ZeroBound and - k = delta - arrlen + k = (delta - arrlen.toBigInt()).toInt() ) ) ) or - exists(Field arr, Expr index, int delta, int arrlen | + exists(Field arr, Expr index, QlBuiltins::BigInt delta, int arrlen | aa.getIndexExpr() = index and aa.getArray() = arr.getAnAccess() and bounded(index, any(ZeroBound z), delta, true, _) and arr.isFinal() and arr.getInitializer().(ArrayCreationExpr).getFirstDimensionSize() = arrlen and - k = delta - arrlen + k = (delta - arrlen.toBigInt()).toInt() ) } diff --git a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql index b4076bee00b5..32a84a2d35a5 100644 --- a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql +++ b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql @@ -21,7 +21,7 @@ import semmle.code.java.dataflow.RangeAnalysis /** Holds if `cond` always evaluates to `isTrue`. */ predicate constCond(BinaryExpr cond, boolean isTrue, Reason reason) { exists( - ComparisonExpr comp, Expr lesser, Expr greater, Bound b, int d1, int d2, Reason r1, Reason r2 + ComparisonExpr comp, Expr lesser, Expr greater, Bound b, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2, Reason r1, Reason r2 | comp = cond and lesser = comp.getLesserOperand() and @@ -49,7 +49,7 @@ predicate constCond(BinaryExpr cond, boolean isTrue, Reason reason) { lhs = eq.getLeftOperand() and rhs = eq.getRightOperand() | - exists(Bound b, int d1, int d2, boolean upper, Reason r1, Reason r2 | + exists(Bound b, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2, boolean upper, Reason r1, Reason r2 | bounded(lhs, b, d1, upper, r1) and bounded(rhs, b, d2, upper.booleanNot(), r2) and isTrue = eq.polarity().booleanNot() and @@ -65,7 +65,7 @@ predicate constCond(BinaryExpr cond, boolean isTrue, Reason reason) { upper = false and d1 > d2 // lhs >= b + d1 > b + d2 >= rhs ) or - exists(Bound b, int d, Reason r1, Reason r2, Reason r3, Reason r4 | + exists(Bound b, QlBuiltins::BigInt d, Reason r1, Reason r2, Reason r3, Reason r4 | bounded(lhs, b, d, true, r1) and bounded(lhs, b, d, false, r2) and bounded(rhs, b, d, true, r3) and diff --git a/java/ql/test/library-tests/constants/constants/Values.java b/java/ql/test/library-tests/constants/constants/Values.java index 7cf88fb9ad82..ac9c920ffb61 100644 --- a/java/ql/test/library-tests/constants/constants/Values.java +++ b/java/ql/test/library-tests/constants/constants/Values.java @@ -31,7 +31,7 @@ void values(final int notConstant) { byte downcast_byte_5 = (byte) (-214); // 42 short downcast_short = (short) 32768; // -32768 int cast_of_non_constant = (int) '*'; //42 - long cast_to_long = (long) 42; //Not handled + long cast_to_long = (long) 42; // 42 int unary_plus = +42; //42 int parameter_plus = +notConstant; //Not constant diff --git a/java/ql/test/library-tests/constants/getIntValue.expected b/java/ql/test/library-tests/constants/getIntValue.expected index 8dfd0fc7841a..0eafe7f98a66 100644 --- a/java/ql/test/library-tests/constants/getIntValue.expected +++ b/java/ql/test/library-tests/constants/getIntValue.expected @@ -19,6 +19,7 @@ | constants/Values.java:31:32:31:44 | (...)... | 42 | | constants/Values.java:32:32:32:44 | (...)... | -32768 | | constants/Values.java:33:36:33:44 | (...)... | 42 | +| constants/Values.java:34:29:34:37 | (...)... | 42 | | constants/Values.java:36:26:36:28 | +... | 42 | | constants/Values.java:39:27:39:29 | -... | -42 | | constants/Values.java:43:27:43:28 | ~... | -1 | diff --git a/java/ql/test/library-tests/constants/getIntValue.ql b/java/ql/test/library-tests/constants/getIntValue.ql index 5fc5b108032f..e360051e998c 100644 --- a/java/ql/test/library-tests/constants/getIntValue.ql +++ b/java/ql/test/library-tests/constants/getIntValue.ql @@ -1,9 +1,9 @@ import semmle.code.java.Variable -from Variable v, CompileTimeConstantExpr init, RefType enclosing, int constant +from Variable v, CompileTimeConstantExpr init, RefType enclosing, QlBuiltins::BigInt constant where v.getInitializer() = init and init.getEnclosingCallable().getDeclaringType() = enclosing and enclosing.hasQualifiedName("constants", "Values") and - constant = init.getIntValue() -select init, constant + constant = init.getBigIntValue() +select init, constant.toString() diff --git a/java/ql/test/library-tests/dataflow/modulus-analysis/ModulusAnalysis.ql b/java/ql/test/library-tests/dataflow/modulus-analysis/ModulusAnalysis.ql index 93e95da4bbe6..3392ab9b7d9c 100644 --- a/java/ql/test/library-tests/dataflow/modulus-analysis/ModulusAnalysis.ql +++ b/java/ql/test/library-tests/dataflow/modulus-analysis/ModulusAnalysis.ql @@ -2,6 +2,6 @@ import java import semmle.code.java.dataflow.ModulusAnalysis import semmle.code.java.dataflow.Bound -from Expr e, Bound b, int delta, int mod +from Expr e, Bound b, QlBuiltins::BigInt delta, QlBuiltins::BigInt mod where exprModulus(e, b, delta, mod) and e.getCompilationUnit().fromSource() select e, b.toString(), delta, mod diff --git a/java/ql/test/library-tests/dataflow/range-analysis/RangeAnalysis.ql b/java/ql/test/library-tests/dataflow/range-analysis/RangeAnalysis.ql index 56a9c81b5f9d..43f9a2a5e37b 100644 --- a/java/ql/test/library-tests/dataflow/range-analysis/RangeAnalysis.ql +++ b/java/ql/test/library-tests/dataflow/range-analysis/RangeAnalysis.ql @@ -7,6 +7,6 @@ private string getDirectionString(boolean d) { result = "lower" and d = false } -from Expr e, Bound b, int delta, boolean upper, Reason reason +from Expr e, Bound b, QlBuiltins::BigInt delta, boolean upper, Reason reason where bounded(e, b, delta, upper, reason) and e.getCompilationUnit().fromSource() select e, b.toString(), delta, getDirectionString(upper), reason diff --git a/shared/rangeanalysis/codeql/rangeanalysis/ModulusAnalysis.qll b/shared/rangeanalysis/codeql/rangeanalysis/ModulusAnalysis.qll index f8b4a94079a7..487672b5477e 100644 --- a/shared/rangeanalysis/codeql/rangeanalysis/ModulusAnalysis.qll +++ b/shared/rangeanalysis/codeql/rangeanalysis/ModulusAnalysis.qll @@ -13,10 +13,8 @@ private import codeql.util.Location private import RangeAnalysis -module ModulusAnalysis< - LocationSig Location, Semantic Sem, DeltaSig D, BoundSig Bounds> -{ - private import internal.RangeUtils::MakeUtils +module ModulusAnalysis Bounds> { + private import internal.RangeUtils::MakeUtils bindingset[pos, v] pragma[inline_late] @@ -28,12 +26,14 @@ module ModulusAnalysis< * Holds if `e + delta` equals `v` at `pos`. */ pragma[nomagic] - private predicate valueFlowStepSsa(Sem::SsaVariable v, SsaReadPosition pos, Sem::Expr e, int delta) { - ssaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v) + private predicate valueFlowStepSsa( + Sem::SsaVariable v, SsaReadPosition pos, Sem::Expr e, QlBuiltins::BigInt delta + ) { + ssaUpdateStep(v, e, delta) and pos.hasReadOfVar(v) or exists(Sem::Guard guard, boolean testIsTrue | hasReadOfVarInlineLate(pos, v) and - guard = eqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and + guard = eqFlowCond(v, e, delta, true, testIsTrue) and guardDirectlyControlsSsaRead(guard, pos, testIsTrue) ) } @@ -64,17 +64,17 @@ module ModulusAnalysis< } /** Gets an expression that is the remainder modulo `mod` of `arg`. */ - private Sem::Expr modExpr(Sem::Expr arg, int mod) { + private Sem::Expr modExpr(Sem::Expr arg, QlBuiltins::BigInt mod) { exists(Sem::RemExpr rem | result = rem and arg = rem.getLeftOperand() and rem.getRightOperand().(Sem::ConstantIntegerExpr).getIntValue() = mod and - mod >= 2 + mod >= 2.toBigInt() ) or exists(Sem::ConstantIntegerExpr c | - mod = 2.pow([1 .. 30]) and - c.getIntValue() = mod - 1 and + mod = 2.toBigInt().pow([1 .. 30]) and + c.getIntValue() = mod - 1.toBigInt() and result.(Sem::BitAndExpr).hasOperands(arg, c) ) } @@ -83,8 +83,10 @@ module ModulusAnalysis< * Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on * its `testIsTrue` branch. */ - private Sem::Guard moduloCheck(Sem::SsaVariable v, int val, int mod, boolean testIsTrue) { - exists(Sem::Expr rem, Sem::ConstantIntegerExpr c, int r, boolean polarity | + private Sem::Guard moduloCheck( + Sem::SsaVariable v, QlBuiltins::BigInt val, QlBuiltins::BigInt mod, boolean testIsTrue + ) { + exists(Sem::Expr rem, Sem::ConstantIntegerExpr c, QlBuiltins::BigInt r, boolean polarity | result.isEquality(rem, c, polarity) and c.getIntValue() = r and rem = modExpr(v.getAUse(), mod) and @@ -92,9 +94,9 @@ module ModulusAnalysis< testIsTrue = polarity and val = r or testIsTrue = polarity.booleanNot() and - mod = 2 and - val = 1 - r and - (r = 0 or r = 1) + mod = 2.toBigInt() and + val = 1.toBigInt() - r and + (r = 0.toBigInt() or r = 1.toBigInt()) ) ) } @@ -102,7 +104,9 @@ module ModulusAnalysis< /** * Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`. */ - private predicate moduloGuardedRead(Sem::SsaVariable v, SsaReadPosition pos, int val, int mod) { + private predicate moduloGuardedRead( + Sem::SsaVariable v, SsaReadPosition pos, QlBuiltins::BigInt val, QlBuiltins::BigInt mod + ) { exists(Sem::Guard guard, boolean testIsTrue | pos.hasReadOfVar(v) and guard = moduloCheck(v, val, mod, testIsTrue) and @@ -118,13 +122,16 @@ module ModulusAnalysis< } /** Holds if `e` is evenly divisible by `factor`. */ - private predicate evenlyDivisibleExpr(Sem::Expr e, int factor) { - exists(Sem::ConstantIntegerExpr c, int k | k = c.getIntValue() | - e.(Sem::MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2 + private predicate evenlyDivisibleExpr(Sem::Expr e, QlBuiltins::BigInt factor) { + exists(Sem::ConstantIntegerExpr c, QlBuiltins::BigInt k | k = c.getIntValue() | + e.(Sem::MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2.toBigInt() or - e.(Sem::ShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0 + e.(Sem::ShiftLeftExpr).getRightOperand() = c and + factor = 2.toBigInt().pow(k.toInt()) and + k > 0.toBigInt() or - e.(Sem::BitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f)) + e.(Sem::BitAndExpr).getAnOperand() = c and + factor = max(int f | andmaskFactor(k.toInt(), f)).toBigInt() ) } @@ -135,31 +142,34 @@ module ModulusAnalysis< * the range `[0 .. mod-1]`. */ bindingset[val, mod] - private int remainder(int val, int mod) { - mod = 0 and result = val + private QlBuiltins::BigInt remainder(QlBuiltins::BigInt val, QlBuiltins::BigInt mod) { + mod = 0.toBigInt() and result = val or - mod > 1 and result = ((val % mod) + mod) % mod + mod > 1.toBigInt() and result = ((val % mod) + mod) % mod } /** * Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`. */ private predicate phiSelfModulus( - Sem::SsaPhiNode phi, Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge, int mod + Sem::SsaPhiNode phi, Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge, + QlBuiltins::BigInt mod ) { - exists(Bounds::SemSsaBound phibound, int v, int m | + exists(Bounds::SemSsaBound phibound, QlBuiltins::BigInt v, QlBuiltins::BigInt m | edge.phiInput(phi, inp) and phibound.getVariable() = phi and ssaModulus(inp, edge, phibound, v, m) and mod = m.gcd(v) and - mod != 1 + mod != 1.toBigInt() ) } /** * Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`. */ - private predicate phiModulusInit(Sem::SsaPhiNode phi, Bounds::SemBound b, int val, int mod) { + private predicate phiModulusInit( + Sem::SsaPhiNode phi, Bounds::SemBound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod + ) { exists(Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) and ssaModulus(inp, edge, b, val, mod) @@ -171,15 +181,18 @@ module ModulusAnalysis< */ pragma[nomagic] private predicate phiModulusRankStep( - Sem::SsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix + Sem::SsaPhiNode phi, Bounds::SemBound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod, int rix ) { // Base case. If any phi input is equal to `b + val` modulo `mod`, that's a // potential congruence class for the phi node. rix = 0 and phiModulusInit(phi, b, val, mod) or - exists(Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge, int v1, int m1 | - mod != 1 and + exists( + Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge, QlBuiltins::BigInt v1, + QlBuiltins::BigInt m1 + | + mod != 1.toBigInt() and val = remainder(v1, mod) | // Recursive case. If `inp` = `b + v2` modulo `m2`, we combine that with @@ -188,7 +201,7 @@ module ModulusAnalysis< // `mod`, we must have that `mod` divides both `m1` and `m2` and that `v1` // equals `v2` modulo `mod`. The largest value of `mod` that satisfies // this is the greatest common divisor of `m1`, `m2`, and `v1 - v2`. - exists(int v2, int m2 | + exists(QlBuiltins::BigInt v2, QlBuiltins::BigInt m2 | rankedPhiInput(phi, inp, edge, rix) and phiModulusRankStep(phi, b, v1, m1, rix - 1) and ssaModulus(inp, edge, b, v2, m2) and @@ -198,7 +211,7 @@ module ModulusAnalysis< // Recursive case. If `inp` = `phi` mod `m2`, we combine that with the // preceding potential congruence class `b + v1` mod `m1`. The result will be // the congruence class modulo the greatest common divisor of `m1` and `m2`. - exists(int m2 | + exists(QlBuiltins::BigInt m2 | rankedPhiInput(phi, inp, edge, rix) and phiModulusRankStep(phi, b, v1, m1, rix - 1) and phiSelfModulus(phi, inp, edge, m2) and @@ -210,7 +223,9 @@ module ModulusAnalysis< /** * Holds if `phi` is equal to `b + val` modulo `mod`. */ - private predicate phiModulus(Sem::SsaPhiNode phi, Bounds::SemBound b, int val, int mod) { + private predicate phiModulus( + Sem::SsaPhiNode phi, Bounds::SemBound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod + ) { exists(int r | maxPhiInputRank(phi, r) and phiModulusRankStep(phi, b, val, mod, r) @@ -221,13 +236,17 @@ module ModulusAnalysis< * Holds if `v` at `pos` is equal to `b + val` modulo `mod`. */ private predicate ssaModulus( - Sem::SsaVariable v, SsaReadPosition pos, Bounds::SemBound b, int val, int mod + Sem::SsaVariable v, SsaReadPosition pos, Bounds::SemBound b, QlBuiltins::BigInt val, + QlBuiltins::BigInt mod ) { phiModulus(v, b, val, mod) and pos.hasReadOfVar(v) or - b.(Bounds::SemSsaBound).getVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0 + b.(Bounds::SemSsaBound).getVariable() = v and + pos.hasReadOfVar(v) and + val = 0.toBigInt() and + mod = 0.toBigInt() or - exists(Sem::Expr e, int val0, int delta | + exists(Sem::Expr e, QlBuiltins::BigInt val0, QlBuiltins::BigInt delta | exprModulus(e, b, val0, mod) and valueFlowStepSsa(v, pos, e, delta) and val = remainder(val0 + delta, mod) @@ -244,11 +263,13 @@ module ModulusAnalysis< * - `mod > 1`: `val` lies within the range `[0 .. mod-1]`. */ cached - predicate exprModulus(Sem::Expr e, Bounds::SemBound b, int val, int mod) { - e = b.getExpr(D::fromInt(val)) and mod = 0 + predicate exprModulus( + Sem::Expr e, Bounds::SemBound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod + ) { + e = b.getExpr(val) and mod = 0.toBigInt() or evenlyDivisibleExpr(e, mod) and - val = 0 and + val = 0.toBigInt() and b instanceof Bounds::SemZeroBound or exists(Sem::SsaVariable v, SsaReadPositionBlock bb | @@ -256,34 +277,40 @@ module ModulusAnalysis< bb.getAnSsaRead(v) = e ) or - exists(Sem::Expr mid, int val0, int delta | + exists(Sem::Expr mid, QlBuiltins::BigInt val0, QlBuiltins::BigInt delta | exprModulus(mid, b, val0, mod) and - valueFlowStep(e, mid, D::fromInt(delta)) and + valueFlowStep(e, mid, delta) and val = remainder(val0 + delta, mod) ) or - exists(Sem::Expr mid, int v, int m1, int m2 | + exists(Sem::Expr mid, QlBuiltins::BigInt v, QlBuiltins::BigInt m1, QlBuiltins::BigInt m2 | exprModulus(mid, b, v, m1) and e = modExpr(mid, m2) and mod = m1.gcd(m2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v, mod) ) or - exists(Sem::ConditionalExpr cond, int v1, int v2, int m1, int m2 | + exists( + Sem::ConditionalExpr cond, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, + QlBuiltins::BigInt m1, QlBuiltins::BigInt m2 + | cond = e and condExprBranchModulus(cond, true, b, v1, m1) and condExprBranchModulus(cond, false, b, v2, m2) and mod = m1.gcd(m2).gcd(v1 - v2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1, mod) ) or - exists(Bounds::SemBound b1, Bounds::SemBound b2, int v1, int v2, int m1, int m2 | + exists( + Bounds::SemBound b1, Bounds::SemBound b2, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, + QlBuiltins::BigInt m1, QlBuiltins::BigInt m2 + | addModulus(e, true, b1, v1, m1) and addModulus(e, false, b2, v2, m2) and mod = m1.gcd(m2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1 + v2, mod) | b = b1 and b2 instanceof Bounds::SemZeroBound @@ -291,22 +318,28 @@ module ModulusAnalysis< b = b2 and b1 instanceof Bounds::SemZeroBound ) or - exists(int v1, int v2, int m1, int m2 | + exists( + QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt m1, QlBuiltins::BigInt m2 + | subModulus(e, true, b, v1, m1) and subModulus(e, false, any(Bounds::SemZeroBound zb), v2, m2) and mod = m1.gcd(m2) and - mod != 1 and + mod != 1.toBigInt() and val = remainder(v1 - v2, mod) ) } private predicate condExprBranchModulus( - Sem::ConditionalExpr cond, boolean branch, Bounds::SemBound b, int val, int mod + Sem::ConditionalExpr cond, boolean branch, Bounds::SemBound b, QlBuiltins::BigInt val, + QlBuiltins::BigInt mod ) { exprModulus(cond.getBranchExpr(branch), b, val, mod) } - private predicate addModulus(Sem::Expr add, boolean isLeft, Bounds::SemBound b, int val, int mod) { + private predicate addModulus( + Sem::Expr add, boolean isLeft, Bounds::SemBound b, QlBuiltins::BigInt val, + QlBuiltins::BigInt mod + ) { exists(Sem::Expr larg, Sem::Expr rarg | nonConstAddition(add, larg, rarg) | exprModulus(larg, b, val, mod) and isLeft = true or @@ -314,7 +347,10 @@ module ModulusAnalysis< ) } - private predicate subModulus(Sem::Expr sub, boolean isLeft, Bounds::SemBound b, int val, int mod) { + private predicate subModulus( + Sem::Expr sub, boolean isLeft, Bounds::SemBound b, QlBuiltins::BigInt val, + QlBuiltins::BigInt mod + ) { exists(Sem::Expr larg, Sem::Expr rarg | nonConstSubtraction(sub, larg, rarg) | exprModulus(larg, b, val, mod) and isLeft = true or diff --git a/shared/rangeanalysis/codeql/rangeanalysis/RangeAnalysis.qll b/shared/rangeanalysis/codeql/rangeanalysis/RangeAnalysis.qll index e178c44cafba..b61b194de7a3 100644 --- a/shared/rangeanalysis/codeql/rangeanalysis/RangeAnalysis.qll +++ b/shared/rangeanalysis/codeql/rangeanalysis/RangeAnalysis.qll @@ -73,7 +73,7 @@ signature module Semantic { } class ConstantIntegerExpr extends Expr { - int getIntValue(); + QlBuiltins::BigInt getIntValue(); } class BinaryExpr extends Expr { @@ -289,7 +289,7 @@ signature module Semantic { /** * Holds if the value of `dest` is known to be `src + delta`. */ - predicate additionalValueFlowStep(Expr dest, Expr src, int delta); + predicate additionalValueFlowStep(Expr dest, Expr src, QlBuiltins::BigInt delta); predicate conversionCannotOverflow(Type fromType, Type toType); } @@ -323,39 +323,21 @@ signature module SignAnalysisSig { signature module ModulusAnalysisSig { class ModBound; - predicate exprModulus(Sem::Expr e, ModBound b, int val, int mod); + predicate exprModulus(Sem::Expr e, ModBound b, QlBuiltins::BigInt val, QlBuiltins::BigInt mod); } -signature module DeltaSig { - bindingset[this] - class Delta; - - bindingset[d] - bindingset[result] - float toFloat(Delta d); - - bindingset[d] - bindingset[result] - int toInt(Delta d); - - bindingset[n] - bindingset[result] - Delta fromInt(int n); - - bindingset[f] - Delta fromFloat(float f); -} - -signature module LangSig { +signature module LangSig { /** * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`). */ - predicate hasConstantBound(Sem::Expr e, D::Delta bound, boolean upper); + predicate hasConstantBound(Sem::Expr e, QlBuiltins::BigInt bound, boolean upper); /** * Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`). */ - predicate additionalBoundFlowStep(Sem::Expr e2, Sem::Expr e1, D::Delta delta, boolean upper); + predicate additionalBoundFlowStep( + Sem::Expr e2, Sem::Expr e1, QlBuiltins::BigInt delta, boolean upper + ); /** * Ignore the bound on this expression. @@ -372,7 +354,7 @@ signature module LangSig { default predicate includeRelativeBounds() { any() } } -signature module BoundSig { +signature module BoundSig { /** * A bound that the range analysis can infer for a variable. This includes * constant bounds represented by the abstract value zero, SSA bounds for when @@ -399,7 +381,7 @@ signature module BoundSig { * value `delta`. For other bounds this gets expressions equal to the bound * and `delta = 0`. */ - Sem::Expr getExpr(D::Delta delta); + Sem::Expr getExpr(QlBuiltins::BigInt delta); } class SemZeroBound extends SemBound; @@ -409,22 +391,21 @@ signature module BoundSig { } } -signature module OverflowSig { +signature module OverflowSig { predicate semExprDoesNotOverflow(boolean positively, Sem::Expr expr); } module RangeStage< - LocationSig Location, Semantic Sem, DeltaSig D, BoundSig Bounds, - OverflowSig OverflowParam, LangSig LangParam, SignAnalysisSig SignAnalysis, + LocationSig Location, Semantic Sem, BoundSig Bounds, + OverflowSig OverflowParam, LangSig LangParam, SignAnalysisSig SignAnalysis, ModulusAnalysisSig ModulusAnalysisParam> { private import Bounds private import LangParam - private import D private import OverflowParam private import SignAnalysis private import ModulusAnalysisParam - private import internal.RangeUtils::MakeUtils + private import internal.RangeUtils::MakeUtils /** * An expression that does conversion, boxing, or unboxing @@ -499,7 +480,9 @@ module RangeStage< * condition. */ cached - predicate semBounded(Sem::Expr e, SemBound b, D::Delta delta, boolean upper, SemReason reason) { + predicate semBounded( + Sem::Expr e, SemBound b, QlBuiltins::BigInt delta, boolean upper, SemReason reason + ) { bounded(e, b, delta, upper, _, _, reason) and bestBound(e, b, delta, upper) } @@ -522,11 +505,11 @@ module RangeStage< * - `upper = true` : `e <= b + delta` * - `upper = false` : `e >= b + delta` */ - private predicate bestBound(Sem::Expr e, SemBound b, D::Delta delta, boolean upper) { - delta = min(D::Delta d | bounded(e, b, d, upper, _, _, _) | d order by D::toFloat(d)) and + private predicate bestBound(Sem::Expr e, SemBound b, QlBuiltins::BigInt delta, boolean upper) { + delta = min(QlBuiltins::BigInt d | bounded(e, b, d, upper, _, _, _) | d) and upper = true or - delta = max(D::Delta d | bounded(e, b, d, upper, _, _, _) | d order by D::toFloat(d)) and + delta = max(QlBuiltins::BigInt d | bounded(e, b, d, upper, _, _, _) | d) and upper = false } @@ -536,7 +519,8 @@ module RangeStage< * - `upper = false` : `v >= e + delta` or `v > e + delta` */ private predicate boundCondition( - Sem::RelationalExpr comp, Sem::SsaVariable v, Sem::Expr e, D::Delta delta, boolean upper + Sem::RelationalExpr comp, Sem::SsaVariable v, Sem::Expr e, QlBuiltins::BigInt delta, + boolean upper ) { comp.getLesserOperand() = ssaRead(v, delta) and e = comp.getGreaterOperand() and @@ -546,14 +530,14 @@ module RangeStage< e = comp.getLesserOperand() and upper = false or - exists(Sem::SubExpr sub, Sem::ConstantIntegerExpr c, D::Delta d | + exists(Sem::SubExpr sub, Sem::ConstantIntegerExpr c, QlBuiltins::BigInt d | // (v - d) - e < c comp.getLesserOperand() = sub and comp.getGreaterOperand() = c and sub.getLeftOperand() = ssaRead(v, d) and sub.getRightOperand() = e and upper = true and - delta = D::fromFloat(D::toFloat(d) + c.getIntValue()) + delta = d + c.getIntValue() or // (v - d) - e > c comp.getGreaterOperand() = sub and @@ -561,7 +545,7 @@ module RangeStage< sub.getLeftOperand() = ssaRead(v, d) and sub.getRightOperand() = e and upper = false and - delta = D::fromFloat(D::toFloat(d) + c.getIntValue()) + delta = d + c.getIntValue() or // e - (v - d) < c comp.getLesserOperand() = sub and @@ -569,7 +553,7 @@ module RangeStage< sub.getLeftOperand() = e and sub.getRightOperand() = ssaRead(v, d) and upper = false and - delta = D::fromFloat(D::toFloat(d) - c.getIntValue()) + delta = d - c.getIntValue() or // e - (v - d) > c comp.getGreaterOperand() = sub and @@ -577,7 +561,7 @@ module RangeStage< sub.getLeftOperand() = e and sub.getRightOperand() = ssaRead(v, d) and upper = true and - delta = D::fromFloat(D::toFloat(d) - c.getIntValue()) + delta = d - c.getIntValue() ) } @@ -586,9 +570,13 @@ module RangeStage< * fixed value modulo some `mod > 1`, such that the comparison can be * strengthened by `strengthen` when evaluating to `testIsTrue`. */ - private predicate modulusComparison(Sem::RelationalExpr comp, boolean testIsTrue, int strengthen) { + private predicate modulusComparison( + Sem::RelationalExpr comp, boolean testIsTrue, QlBuiltins::BigInt strengthen + ) { exists( - ModBound b, int v1, int v2, int mod1, int mod2, int mod, boolean resultIsStrict, int d, int k + ModBound b, QlBuiltins::BigInt v1, QlBuiltins::BigInt v2, QlBuiltins::BigInt mod1, + QlBuiltins::BigInt mod2, QlBuiltins::BigInt mod, boolean resultIsStrict, QlBuiltins::BigInt d, + QlBuiltins::BigInt k | // If `x <= y` and `x =(mod) b + v1` and `y =(mod) b + v2` then // `0 <= y - x =(mod) v2 - v1`. By choosing `k =(mod) v2 - v1` with @@ -599,7 +587,7 @@ module RangeStage< exprModulus(comp.getLesserOperand(), b, v1, mod1) and exprModulus(comp.getGreaterOperand(), b, v2, mod2) and mod = mod1.gcd(mod2) and - mod != 1 and + mod != 1.toBigInt() and (testIsTrue = true or testIsTrue = false) and ( if comp.isStrict() @@ -607,9 +595,9 @@ module RangeStage< else resultIsStrict = testIsTrue.booleanNot() ) and ( - resultIsStrict = true and d = 1 + resultIsStrict = true and d = 1.toBigInt() or - resultIsStrict = false and d = 0 + resultIsStrict = false and d = 0.toBigInt() ) and ( testIsTrue = true and k = v2 - v1 @@ -628,11 +616,11 @@ module RangeStage< * - `upper = false` : `v >= e + delta` */ private Sem::Guard boundFlowCond( - Sem::SsaVariable v, Sem::Expr e, D::Delta delta, boolean upper, boolean testIsTrue + Sem::SsaVariable v, Sem::Expr e, QlBuiltins::BigInt delta, boolean upper, boolean testIsTrue ) { exists( - Sem::RelationalExpr comp, D::Delta d1, float d2, float d3, int strengthen, - boolean compIsUpper, boolean resultIsStrict + Sem::RelationalExpr comp, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2, QlBuiltins::BigInt d3, + int strengthen, boolean compIsUpper, boolean resultIsStrict | comp = result.asExpr() and boundCondition(comp, v, e, d1, compIsUpper) and @@ -654,17 +642,19 @@ module RangeStage< else strengthen = 0 ) and ( - exists(int k | modulusComparison(comp, testIsTrue, k) and d2 = strengthen * k) + exists(QlBuiltins::BigInt k | + modulusComparison(comp, testIsTrue, k) and d2 = strengthen.toBigInt() * k + ) or - not modulusComparison(comp, testIsTrue, _) and d2 = 0 + not modulusComparison(comp, testIsTrue, _) and d2 = 0.toBigInt() ) and // A strict inequality `x < y` can be strengthened to `x <= y - 1`. ( - resultIsStrict = true and d3 = strengthen + resultIsStrict = true and d3 = strengthen.toBigInt() or - resultIsStrict = false and d3 = 0 + resultIsStrict = false and d3 = 0.toBigInt() ) and - delta = D::fromFloat(D::toFloat(d1) + d2 + d3) + delta = d1 + d2 + d3 ) or exists(boolean testIsTrue0 | @@ -677,11 +667,11 @@ module RangeStage< or // guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and // exists a guard `guardEq` such that `v = v2 - d1 + d2`. - exists(Sem::SsaVariable v2, D::Delta oldDelta, float d | + exists(Sem::SsaVariable v2, QlBuiltins::BigInt oldDelta, QlBuiltins::BigInt d | // equality needs to control guard result.getBasicBlock() = eqSsaCondDirectlyControls(v, v2, d) and result = boundFlowCond(v2, e, oldDelta, upper, testIsTrue) and - delta = D::fromFloat(D::toFloat(oldDelta) + d) + delta = oldDelta + d ) } @@ -690,11 +680,11 @@ module RangeStage< */ pragma[nomagic] private Sem::BasicBlock eqSsaCondDirectlyControls( - Sem::SsaVariable v1, Sem::SsaVariable v2, float delta + Sem::SsaVariable v1, Sem::SsaVariable v2, QlBuiltins::BigInt delta ) { - exists(Sem::Guard guardEq, D::Delta d1, D::Delta d2, boolean eqIsTrue | + exists(Sem::Guard guardEq, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2, boolean eqIsTrue | guardEq = eqFlowCond(v1, ssaRead(v2, d1), d2, true, eqIsTrue) and - delta = D::toFloat(d2) - D::toFloat(d1) and + delta = d2 - d1 and guardEq.directlyControls(result, eqIsTrue) ) } @@ -735,7 +725,7 @@ module RangeStage< * - `upper = false` : `v >= e + delta` */ private predicate boundFlowStepSsa( - Sem::SsaVariable v, SsaReadPosition pos, Sem::Expr e, D::Delta delta, boolean upper, + Sem::SsaVariable v, SsaReadPosition pos, Sem::Expr e, QlBuiltins::BigInt delta, boolean upper, SemReason reason ) { ssaUpdateStep(v, e, delta) and @@ -753,7 +743,7 @@ module RangeStage< /** Holds if `v != e + delta` at `pos` and `v` is of integral type. */ private predicate unequalFlowStepIntegralSsa( - Sem::SsaVariable v, SsaReadPosition pos, Sem::Expr e, D::Delta delta, SemReason reason + Sem::SsaVariable v, SsaReadPosition pos, Sem::Expr e, QlBuiltins::BigInt delta, SemReason reason ) { Sem::getSsaType(v) instanceof Sem::IntegerType and exists(Sem::Guard guard, boolean testIsTrue | @@ -779,7 +769,9 @@ module RangeStage< * - `upper = true` : `e2 <= e1 + delta` * - `upper = false` : `e2 >= e1 + delta` */ - private predicate boundFlowStep(Sem::Expr e2, Sem::Expr e1, D::Delta delta, boolean upper) { + private predicate boundFlowStep( + Sem::Expr e2, Sem::Expr e1, QlBuiltins::BigInt delta, boolean upper + ) { // Constants have easy, base-case bounds, so let's not infer any recursive bounds. not e2 instanceof Sem::ConstantIntegerExpr and ( @@ -787,7 +779,7 @@ module RangeStage< upper = [true, false] or e2.(SafeCastExpr).getOperand() = e1 and - delta = D::fromInt(0) and + delta = 0.toBigInt() and upper = [true, false] or javaCompatibility() and @@ -799,37 +791,37 @@ module RangeStage< // `x instanceof ConstantIntegerExpr` is covered by valueFlowStep not x instanceof Sem::ConstantIntegerExpr and if strictlyPositiveIntegralExpr(x) - then upper = true and delta = D::fromInt(-1) + then upper = true and delta = -1.toBigInt() else if semPositive(x) - then upper = true and delta = D::fromInt(0) + then upper = true and delta = 0.toBigInt() else if strictlyNegativeIntegralExpr(x) - then upper = false and delta = D::fromInt(1) + then upper = false and delta = 1.toBigInt() else if semNegative(x) - then upper = false and delta = D::fromInt(0) + then upper = false and delta = 0.toBigInt() else none() ) or e2.(Sem::RemExpr).getRightOperand() = e1 and semPositive(e1) and - delta = D::fromInt(-1) and + delta = -1.toBigInt() and upper = true or e2.(Sem::RemExpr).getLeftOperand() = e1 and semPositive(e1) and - delta = D::fromInt(0) and + delta = 0.toBigInt() and upper = true or e2.(Sem::BitAndExpr).getAnOperand() = e1 and semPositive(e1) and - delta = D::fromInt(0) and + delta = 0.toBigInt() and upper = true or e2.(Sem::BitOrExpr).getAnOperand() = e1 and semPositive(e2) and - delta = D::fromInt(0) and + delta = 0.toBigInt() and upper = false or additionalBoundFlowStep(e2, e1, delta, upper) @@ -837,16 +829,18 @@ module RangeStage< } /** Holds if `e2 = e1 * factor` and `factor > 0`. */ - private predicate boundFlowStepMul(Sem::Expr e2, Sem::Expr e1, D::Delta factor) { + private predicate boundFlowStepMul(Sem::Expr e2, Sem::Expr e1, QlBuiltins::BigInt factor) { not e2 instanceof Sem::ConstantIntegerExpr and - exists(Sem::ConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 | - e2.(Sem::MulExpr).hasOperands(e1, c) and factor = D::fromInt(k) + exists(Sem::ConstantIntegerExpr c, QlBuiltins::BigInt k | + k = c.getIntValue() and k > 0.toBigInt() + | + e2.(Sem::MulExpr).hasOperands(e1, c) and factor = k or exists(Sem::ShiftLeftExpr e | e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and - factor = D::fromInt(2.pow(k)) + factor = 2.toBigInt().pow(k.toInt()) ) ) } @@ -857,11 +851,11 @@ module RangeStage< * This conflates division, right shift, and unsigned right shift and is * therefore only valid for non-negative numbers. */ - private predicate boundFlowStepDiv(Sem::Expr e2, Sem::Expr e1, D::Delta factor) { + private predicate boundFlowStepDiv(Sem::Expr e2, Sem::Expr e1, QlBuiltins::BigInt factor) { not e2 instanceof Sem::ConstantIntegerExpr and Sem::getExprType(e2) instanceof Sem::IntegerType and - exists(Sem::ConstantIntegerExpr c, D::Delta k | - k = D::fromInt(c.getIntValue()) and D::toFloat(k) > 0 + exists(Sem::ConstantIntegerExpr c, QlBuiltins::BigInt k | + k = c.getIntValue() and k > 0.toBigInt() | exists(Sem::DivExpr e | e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k @@ -871,14 +865,14 @@ module RangeStage< e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and - factor = D::fromInt(2.pow(D::toInt(k))) + factor = 2.toBigInt().pow(k.toInt()) ) or exists(Sem::ShiftRightUnsignedExpr e | e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and - factor = D::fromInt(2.pow(D::toInt(k))) + factor = 2.toBigInt().pow(k.toInt()) ) ) } @@ -889,28 +883,28 @@ module RangeStage< * - `upper = false` : `v >= b + delta` */ private predicate boundedSsa( - Sem::SsaVariable v, SemBound b, D::Delta delta, SsaReadPosition pos, boolean upper, - boolean fromBackEdge, D::Delta origdelta, SemReason reason + Sem::SsaVariable v, SemBound b, QlBuiltins::BigInt delta, SsaReadPosition pos, boolean upper, + boolean fromBackEdge, QlBuiltins::BigInt origdelta, SemReason reason ) { - exists(Sem::Expr mid, D::Delta d1, D::Delta d2, SemReason r1, SemReason r2 | + exists(Sem::Expr mid, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2, SemReason r1, SemReason r2 | boundFlowStepSsa(v, pos, mid, d1, upper, r1) and bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and // upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta // upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta - delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2)) and + delta = d1 + d2 and (if r1 instanceof SemNoReason then reason = r2 else reason = r1) ) or - exists(D::Delta d, SemReason r1, SemReason r2 | + exists(QlBuiltins::BigInt d, SemReason r1, SemReason r2 | boundedSsa(v, b, d, pos, upper, fromBackEdge, origdelta, r2) or boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2) | unequalIntegralSsa(v, b, d, pos, r1) and ( - upper = true and delta = D::fromFloat(D::toFloat(d) - 1) + upper = true and delta = d - 1.toBigInt() or - upper = false and delta = D::fromFloat(D::toFloat(d) + 1) + upper = false and delta = d + 1.toBigInt() ) and ( reason = r1 @@ -924,24 +918,24 @@ module RangeStage< * Holds if `v != b + delta` at `pos` and `v` is of integral type. */ private predicate unequalIntegralSsa( - Sem::SsaVariable v, SemBound b, D::Delta delta, SsaReadPosition pos, SemReason reason + Sem::SsaVariable v, SemBound b, QlBuiltins::BigInt delta, SsaReadPosition pos, SemReason reason ) { - exists(Sem::Expr e, D::Delta d1, D::Delta d2 | + exists(Sem::Expr e, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2 | unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and bounded(e, b, d2, true, _, _, _) and bounded(e, b, d2, false, _, _, _) and - delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2)) + delta = d1 + d2 ) } /** Weakens a delta to lie in the range `[-1..1]`. */ bindingset[delta, upper] - private D::Delta weakenDelta(boolean upper, D::Delta delta) { - delta = D::fromFloat([-1 .. 1]) and result = delta + private QlBuiltins::BigInt weakenDelta(boolean upper, QlBuiltins::BigInt delta) { + delta = ([-1 .. 1]).toBigInt() and result = delta or - upper = true and result = D::fromFloat(-1) and D::toFloat(delta) < -1 + upper = true and result = -1.toBigInt() and delta < -1.toBigInt() or - upper = false and result = D::fromFloat(1) and D::toFloat(delta) > 1 + upper = false and result = 1.toBigInt() and delta > 1.toBigInt() } /** @@ -952,19 +946,20 @@ module RangeStage< */ private predicate boundedPhiInp( Sem::SsaPhiNode phi, Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge, SemBound b, - D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta, SemReason reason + QlBuiltins::BigInt delta, boolean upper, boolean fromBackEdge, QlBuiltins::BigInt origdelta, + SemReason reason ) { edge.phiInput(phi, inp) and - exists(D::Delta d, boolean fromBackEdge0 | + exists(QlBuiltins::BigInt d, boolean fromBackEdge0 | boundedSsa(inp, b, d, edge, upper, fromBackEdge0, origdelta, reason) or boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason) or b.(SemSsaBound).getVariable() = inp and - d = D::fromFloat(0) and + d = 0.toBigInt() and (upper = true or upper = false) and fromBackEdge0 = false and - origdelta = D::fromFloat(0) and + origdelta = 0.toBigInt() and reason = TSemNoReason() | if backEdge(phi, inp, edge) @@ -972,9 +967,7 @@ module RangeStage< fromBackEdge = true and ( fromBackEdge0 = true and - delta = - D::fromFloat(D::toFloat(weakenDelta(upper, - D::fromFloat(D::toFloat(d) - D::toFloat(origdelta)))) + D::toFloat(origdelta)) + delta = weakenDelta(upper, d - origdelta) + origdelta or fromBackEdge0 = false and delta = d ) @@ -995,7 +988,7 @@ module RangeStage< pragma[noinline] private predicate boundedPhiInp1( Sem::SsaPhiNode phi, SemBound b, boolean upper, Sem::SsaVariable inp, - SsaReadPositionPhiInputEdge edge, D::Delta delta + SsaReadPositionPhiInputEdge edge, QlBuiltins::BigInt delta ) { boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _) } @@ -1009,13 +1002,13 @@ module RangeStage< private predicate selfBoundedPhiInp( Sem::SsaPhiNode phi, Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge, boolean upper ) { - exists(D::Delta d, SemSsaBound phibound | + exists(QlBuiltins::BigInt d, SemSsaBound phibound | phibound.getVariable() = phi and boundedPhiInp(phi, inp, edge, phibound, d, upper, _, _, _) and ( - upper = true and D::toFloat(d) <= 0 + upper = true and d <= 0.toBigInt() or - upper = false and D::toFloat(d) >= 0 + upper = false and d >= 0.toBigInt() ) ) } @@ -1028,8 +1021,8 @@ module RangeStage< */ pragma[noinline] private predicate boundedPhiCand( - Sem::SsaPhiNode phi, boolean upper, SemBound b, D::Delta delta, boolean fromBackEdge, - D::Delta origdelta, SemReason reason + Sem::SsaPhiNode phi, boolean upper, SemBound b, QlBuiltins::BigInt delta, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason ) { boundedPhiInp(phi, _, _, b, delta, upper, fromBackEdge, origdelta, reason) } @@ -1039,17 +1032,18 @@ module RangeStage< * `inp` along `edge`. */ private predicate boundedPhiCandValidForEdge( - Sem::SsaPhiNode phi, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, - D::Delta origdelta, SemReason reason, Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge + Sem::SsaPhiNode phi, SemBound b, QlBuiltins::BigInt delta, boolean upper, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason, Sem::SsaVariable inp, + SsaReadPositionPhiInputEdge edge ) { boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and ( - exists(D::Delta d | boundedPhiInp1(phi, b, upper, inp, edge, d) | - upper = true and D::toFloat(d) <= D::toFloat(delta) + exists(QlBuiltins::BigInt d | boundedPhiInp1(phi, b, upper, inp, edge, d) | + upper = true and d <= delta ) or - exists(D::Delta d | boundedPhiInp1(phi, b, upper, inp, edge, d) | - upper = false and D::toFloat(d) >= D::toFloat(delta) + exists(QlBuiltins::BigInt d | boundedPhiInp1(phi, b, upper, inp, edge, d) | + upper = false and d >= delta ) or selfBoundedPhiInp(phi, inp, edge, upper) @@ -1063,8 +1057,8 @@ module RangeStage< */ pragma[nomagic] private predicate boundedPhiRankStep( - Sem::SsaPhiNode phi, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, - D::Delta origdelta, SemReason reason, int rix + Sem::SsaPhiNode phi, SemBound b, QlBuiltins::BigInt delta, boolean upper, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason, int rix ) { exists(Sem::SsaVariable inp, SsaReadPositionPhiInputEdge edge | rankedPhiInput(phi, inp, edge, rix) and @@ -1082,8 +1076,8 @@ module RangeStage< * - `upper = false` : `phi >= b + delta` */ private predicate boundedPhi( - Sem::SsaPhiNode phi, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, - D::Delta origdelta, SemReason reason + Sem::SsaPhiNode phi, SemBound b, QlBuiltins::BigInt delta, boolean upper, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason ) { exists(int r | maxPhiInputRank(phi, r) and @@ -1102,7 +1096,7 @@ module RangeStage< * Holds if `e` has an intrinsic upper (for `upper = true`) or lower * (for `upper = false`) bound of `b + delta` as a base case for range analysis. */ - private predicate baseBound(Sem::Expr e, SemBound b, D::Delta delta, boolean upper) { + private predicate baseBound(Sem::Expr e, SemBound b, QlBuiltins::BigInt delta, boolean upper) { includeBound(b) and ( e = b.getExpr(delta) and @@ -1112,7 +1106,7 @@ module RangeStage< b instanceof SemZeroBound or upper = false and - delta = D::fromInt(0) and + delta = 0.toBigInt() and semPositive(e.(Sem::BitAndExpr).getAnOperand()) and b instanceof SemZeroBound ) @@ -1125,28 +1119,28 @@ module RangeStage< * `upper = false` this means that the cast will not underflow. */ private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) { - exists(D::Delta bound | + exists(QlBuiltins::BigInt bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) | - upper = true and D::toFloat(bound) <= cast.getUpperBound() + upper = true and bound <= cast.getUpperBound().floor().toBigInt() or - upper = false and D::toFloat(bound) >= cast.getLowerBound() + upper = false and bound >= cast.getLowerBound().(int).toBigInt() ) } pragma[noinline] private predicate boundedCastExpr( - NarrowingCastExpr cast, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, - D::Delta origdelta, SemReason reason + NarrowingCastExpr cast, SemBound b, QlBuiltins::BigInt delta, boolean upper, + boolean fromBackEdge, QlBuiltins::BigInt origdelta, SemReason reason ) { bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason) } pragma[nomagic] private predicate initialBoundedUpper(Sem::Expr e) { - exists(D::Delta d | + exists(QlBuiltins::BigInt d | initialBounded(e, _, d, false, _, _, _) and - D::toFloat(d) >= 0 + d >= 0.toBigInt() ) } @@ -1161,9 +1155,9 @@ module RangeStage< pragma[nomagic] private predicate initialBoundedLower(Sem::Expr e) { - exists(D::Delta d | + exists(QlBuiltins::BigInt d | initialBounded(e, _, d, true, _, _, _) and - D::toFloat(d) <= 0 + d <= 0.toBigInt() ) } @@ -1177,8 +1171,8 @@ module RangeStage< } predicate bounded( - Sem::Expr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, - D::Delta origdelta, SemReason reason + Sem::Expr e, SemBound b, QlBuiltins::BigInt delta, boolean upper, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason ) { initialBounded(e, b, delta, upper, fromBackEdge, origdelta, reason) and noOverflow(e, upper) @@ -1218,18 +1212,6 @@ module RangeStage< expr instanceof Sem::PreIncExpr } - /** - * Computes a normal form of `x` where -0.0 has changed to +0.0. This can be - * needed on the lesser side of a floating-point comparison or on both sides of - * a floating point equality because QL does not follow IEEE in floating-point - * comparisons but instead defines -0.0 to be less than and distinct from 0.0. - */ - bindingset[x] - private float normalizeFloatUp(float x) { result = x + 0.0 } - - bindingset[x, y] - private float truncatingDiv(float x, float y) { result = (x - (x % y)) / y } - /** * Holds if `e1 + delta` is a valid bound for `e2`. * - `upper = true` : `e2 <= e1 + delta` @@ -1237,7 +1219,7 @@ module RangeStage< * * This is restricted to simple forward-flowing steps and disregards phi-nodes. */ - private predicate preBoundStep(Sem::Expr e2, Sem::Expr e1, D::Delta delta, boolean upper) { + private predicate preBoundStep(Sem::Expr e2, Sem::Expr e1, QlBuiltins::BigInt delta, boolean upper) { boundFlowStep(e2, e1, delta, upper) or exists(Sem::SsaVariable v, SsaReadPositionBlock bb | @@ -1266,7 +1248,9 @@ module RangeStage< } pragma[nomagic] - private predicate relevantPreBoundStep(Sem::Expr e2, Sem::Expr e1, D::Delta delta, boolean upper) { + private predicate relevantPreBoundStep( + Sem::Expr e2, Sem::Expr e1, QlBuiltins::BigInt delta, boolean upper + ) { preBoundStep(e2, e1, delta, upper) and reachesBoundMergepoint(e2, upper) } @@ -1290,21 +1274,21 @@ module RangeStage< * ... * ``` */ - private predicate preBounded(Sem::Expr e, SemBound b, D::Delta delta, boolean upper) { + private predicate preBounded(Sem::Expr e, SemBound b, QlBuiltins::BigInt delta, boolean upper) { baseBound(e, b, delta, upper) or - exists(Sem::Expr mid, D::Delta d1, D::Delta d2 | + exists(Sem::Expr mid, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2 | relevantPreBoundStep(e, mid, d1, upper) and preBounded(mid, b, d2, upper) and - delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2)) + delta = d1 + d2 ) } - private predicate bestPreBound(Sem::Expr e, SemBound b, D::Delta delta, boolean upper) { - delta = min(D::Delta d | preBounded(e, b, d, upper) | d order by D::toFloat(d)) and + private predicate bestPreBound(Sem::Expr e, SemBound b, QlBuiltins::BigInt delta, boolean upper) { + delta = min(QlBuiltins::BigInt d | preBounded(e, b, d, upper) | d) and upper = true or - delta = max(D::Delta d | preBounded(e, b, d, upper) | d order by D::toFloat(d)) and + delta = max(QlBuiltins::BigInt d | preBounded(e, b, d, upper) | d) and upper = false } @@ -1314,15 +1298,15 @@ module RangeStage< * - `upper = false` : `e >= b + delta` */ predicate initialBounded( - Sem::Expr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, - D::Delta origdelta, SemReason reason + Sem::Expr e, SemBound b, QlBuiltins::BigInt delta, boolean upper, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason ) { not ignoreExprBound(e) and // ignore poor bounds - not exists(D::Delta d | bestPreBound(e, b, d, upper) | - D::toFloat(delta) > D::toFloat(d) and upper = true + not exists(QlBuiltins::BigInt d | bestPreBound(e, b, d, upper) | + delta > d and upper = true or - D::toFloat(delta) < D::toFloat(d) and upper = false + delta < d and upper = false ) and ( baseBound(e, b, delta, upper) and @@ -1335,12 +1319,12 @@ module RangeStage< bb.getAnSsaRead(v) = e ) or - exists(Sem::Expr mid, D::Delta d1, D::Delta d2 | + exists(Sem::Expr mid, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2 | boundFlowStep(e, mid, d1, upper) and bounded(mid, b, d2, upper, fromBackEdge, origdelta, reason) and // upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta // upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta - delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2)) + delta = d1 + d2 ) or exists(Sem::SsaPhiNode phi | @@ -1348,19 +1332,19 @@ module RangeStage< e = phi.getAUse() ) or - exists(Sem::Expr mid, D::Delta factor, D::Delta d | + exists(Sem::Expr mid, QlBuiltins::BigInt factor, QlBuiltins::BigInt d | boundFlowStepMul(e, mid, factor) and bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and b instanceof SemZeroBound and - delta = D::fromFloat(D::toFloat(d) * D::toFloat(factor)) + delta = d * factor ) or - exists(Sem::Expr mid, D::Delta factor, D::Delta d | + exists(Sem::Expr mid, QlBuiltins::BigInt factor, QlBuiltins::BigInt d | boundFlowStepDiv(e, mid, factor) and bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and b instanceof SemZeroBound and - D::toFloat(d) >= 0 and - delta = D::fromFloat(truncatingDiv(D::toFloat(d), D::toFloat(factor))) + d >= 0.toBigInt() and + delta = d / factor ) or exists(NarrowingCastExpr cast | @@ -1370,8 +1354,8 @@ module RangeStage< ) or exists( - Sem::ConditionalExpr cond, D::Delta d1, D::Delta d2, boolean fbe1, boolean fbe2, - D::Delta od1, D::Delta od2, SemReason r1, SemReason r2 + Sem::ConditionalExpr cond, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2, boolean fbe1, + boolean fbe2, QlBuiltins::BigInt od1, QlBuiltins::BigInt od2, SemReason r1, SemReason r2 | cond = e and boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and @@ -1382,28 +1366,29 @@ module RangeStage< delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2 ) | - upper = true and delta = D::fromFloat(D::toFloat(d1).maximum(D::toFloat(d2))) + upper = true and delta = d1.maximum(d2) or - upper = false and delta = D::fromFloat(D::toFloat(d1).minimum(D::toFloat(d2))) + upper = false and delta = d1.minimum(d2) ) or not javaCompatibility() and - exists(Sem::Expr mid, D::Delta d, float f | + exists(Sem::Expr mid, QlBuiltins::BigInt d, QlBuiltins::BigInt f | e.(Sem::NegateExpr).getOperand() = mid and b instanceof SemZeroBound and bounded(mid, b, d, upper.booleanNot(), fromBackEdge, origdelta, reason) and - f = normalizeFloatUp(-D::toFloat(d)) and - delta = D::fromFloat(f) and - if semPositive(e) then f >= 0 else any() + f = -d and + delta = f and + if semPositive(e) then f >= 0.toBigInt() else any() ) or exists( - SemBound bLeft, SemBound bRight, D::Delta dLeft, D::Delta dRight, boolean fbeLeft, - boolean fbeRight, D::Delta odLeft, D::Delta odRight, SemReason rLeft, SemReason rRight + SemBound bLeft, SemBound bRight, QlBuiltins::BigInt dLeft, QlBuiltins::BigInt dRight, + boolean fbeLeft, boolean fbeRight, QlBuiltins::BigInt odLeft, QlBuiltins::BigInt odRight, + SemReason rLeft, SemReason rRight | boundedAddOperand(e, upper, bLeft, false, dLeft, fbeLeft, odLeft, rLeft) and boundedAddOperand(e, upper, bRight, true, dRight, fbeRight, odRight, rRight) and - delta = D::fromFloat(D::toFloat(dLeft) + D::toFloat(dRight)) and + delta = dLeft + dRight and fromBackEdge = fbeLeft.booleanOr(fbeRight) | b = bLeft and origdelta = odLeft and reason = rLeft and bRight instanceof SemZeroBound @@ -1412,7 +1397,9 @@ module RangeStage< ) or not javaCompatibility() and - exists(D::Delta dLeft, D::Delta dRight, boolean fbeLeft, boolean fbeRight | + exists( + QlBuiltins::BigInt dLeft, QlBuiltins::BigInt dRight, boolean fbeLeft, boolean fbeRight + | boundedSubOperandLeft(e, upper, b, dLeft, fbeLeft, origdelta, reason) and boundedSubOperandRight(e, upper, dRight, fbeRight) and // when `upper` is `true` we have: @@ -1425,14 +1412,15 @@ module RangeStage< // right <= 0 + dRight // left - right >= b + dLeft - (0 + dRight) // = b + (dLeft - dRight) - delta = D::fromFloat(D::toFloat(dLeft) - D::toFloat(dRight)) and + delta = dLeft - dRight and fromBackEdge = fbeLeft.booleanOr(fbeRight) ) or not javaCompatibility() and exists( - Sem::RemExpr rem, D::Delta d_max, D::Delta d1, D::Delta d2, boolean fbe1, boolean fbe2, - D::Delta od1, D::Delta od2, SemReason r1, SemReason r2 + Sem::RemExpr rem, QlBuiltins::BigInt d_max, QlBuiltins::BigInt d1, QlBuiltins::BigInt d2, + boolean fbe1, boolean fbe2, QlBuiltins::BigInt od1, QlBuiltins::BigInt od2, SemReason r1, + SemReason r2 | rem = e and b instanceof SemZeroBound and @@ -1441,7 +1429,7 @@ module RangeStage< boundedRemExpr(rem, true, d1, fbe1, od1, r1) and boundedRemExpr(rem, false, d2, fbe2, od2, r2) and ( - if D::toFloat(d1).abs() > D::toFloat(d2).abs() + if (d1).abs() > (d2).abs() then ( d_max = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1 ) else ( @@ -1449,19 +1437,19 @@ module RangeStage< ) ) | - upper = true and delta = D::fromFloat(D::toFloat(d_max).abs() - 1) + upper = true and delta = d_max.abs() - 1.toBigInt() or - upper = false and delta = D::fromFloat(-D::toFloat(d_max).abs() + 1) + upper = false and delta = -d_max.abs() + 1.toBigInt() ) or not javaCompatibility() and exists( - D::Delta dLeft, D::Delta dRight, boolean fbeLeft, boolean fbeRight, D::Delta odLeft, - D::Delta odRight, SemReason rLeft, SemReason rRight + QlBuiltins::BigInt dLeft, QlBuiltins::BigInt dRight, boolean fbeLeft, boolean fbeRight, + QlBuiltins::BigInt odLeft, QlBuiltins::BigInt odRight, SemReason rLeft, SemReason rRight | boundedMulOperand(e, upper, true, dLeft, fbeLeft, odLeft, rLeft) and boundedMulOperand(e, upper, false, dRight, fbeRight, odRight, rRight) and - delta = D::fromFloat(D::toFloat(dLeft) * D::toFloat(dRight)) and + delta = ((dLeft) * (dRight)) and fromBackEdge = fbeLeft.booleanOr(fbeRight) | b instanceof SemZeroBound and origdelta = odLeft and reason = rLeft @@ -1473,16 +1461,16 @@ module RangeStage< pragma[nomagic] private predicate boundedConditionalExpr( - Sem::ConditionalExpr cond, SemBound b, boolean upper, boolean branch, D::Delta delta, - boolean fromBackEdge, D::Delta origdelta, SemReason reason + Sem::ConditionalExpr cond, SemBound b, boolean upper, boolean branch, QlBuiltins::BigInt delta, + boolean fromBackEdge, QlBuiltins::BigInt origdelta, SemReason reason ) { bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason) } pragma[nomagic] private predicate boundedAddOperand( - Sem::AddExpr add, boolean upper, SemBound b, boolean isLeft, D::Delta delta, - boolean fromBackEdge, D::Delta origdelta, SemReason reason + Sem::AddExpr add, boolean upper, SemBound b, boolean isLeft, QlBuiltins::BigInt delta, + boolean fromBackEdge, QlBuiltins::BigInt origdelta, SemReason reason ) { // `valueFlowStep` already handles the case where one of the operands is a constant. not valueFlowStep(add, _, _) and @@ -1501,8 +1489,8 @@ module RangeStage< */ pragma[nomagic] private predicate boundedSubOperandLeft( - Sem::SubExpr sub, boolean upper, SemBound b, D::Delta delta, boolean fromBackEdge, - D::Delta origdelta, SemReason reason + Sem::SubExpr sub, boolean upper, SemBound b, QlBuiltins::BigInt delta, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason ) { // `valueFlowStep` already handles the case where one of the operands is a constant. not valueFlowStep(sub, _, _) and @@ -1518,7 +1506,7 @@ module RangeStage< */ pragma[nomagic] private predicate boundedSubOperandRight( - Sem::SubExpr sub, boolean upper, D::Delta delta, boolean fromBackEdge + Sem::SubExpr sub, boolean upper, QlBuiltins::BigInt delta, boolean fromBackEdge ) { // `valueFlowStep` already handles the case where one of the operands is a constant. not valueFlowStep(sub, _, _) and @@ -1528,8 +1516,8 @@ module RangeStage< pragma[nomagic] private predicate boundedRemExpr( - Sem::RemExpr rem, boolean upper, D::Delta delta, boolean fromBackEdge, D::Delta origdelta, - SemReason reason + Sem::RemExpr rem, boolean upper, QlBuiltins::BigInt delta, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason ) { bounded(rem.getRightOperand(), any(SemZeroBound zb), delta, upper, fromBackEdge, origdelta, reason) @@ -1626,8 +1614,8 @@ module RangeStage< */ pragma[nomagic] private predicate boundedMulOperand( - Sem::MulExpr mul, boolean upper, boolean isLeft, D::Delta delta, boolean fromBackEdge, - D::Delta origdelta, SemReason reason + Sem::MulExpr mul, boolean upper, boolean isLeft, QlBuiltins::BigInt delta, boolean fromBackEdge, + QlBuiltins::BigInt origdelta, SemReason reason ) { exists(boolean upperLeft, boolean upperRight, Sem::Expr left, Sem::Expr right | boundedMulOperandCand(mul, left, right, upper, upperLeft, upperRight) diff --git a/shared/rangeanalysis/codeql/rangeanalysis/internal/RangeUtils.qll b/shared/rangeanalysis/codeql/rangeanalysis/internal/RangeUtils.qll index dc1014a886ed..1249281b283a 100644 --- a/shared/rangeanalysis/codeql/rangeanalysis/internal/RangeUtils.qll +++ b/shared/rangeanalysis/codeql/rangeanalysis/internal/RangeUtils.qll @@ -1,38 +1,38 @@ private import codeql.rangeanalysis.RangeAnalysis -module MakeUtils { +module MakeUtils { private import Lang /** * Gets an expression that equals `v - d`. */ - Expr ssaRead(SsaVariable v, D::Delta delta) { - result = v.getAUse() and delta = D::fromInt(0) + Expr ssaRead(SsaVariable v, QlBuiltins::BigInt delta) { + result = v.getAUse() and delta = 0.toBigInt() or - exists(D::Delta d1, ConstantIntegerExpr c | + exists(QlBuiltins::BigInt d1, ConstantIntegerExpr c | result.(AddExpr).hasOperands(ssaRead(v, d1), c) and - delta = D::fromFloat(D::toFloat(d1) - c.getIntValue()) and + delta = d1 - c.getIntValue() and // In the scope of `x += ..`, which is SSA translated as `x2 = x1 + ..`, // the variable `x1` is shadowed by `x2`, so there's no need to view this // as a read of `x1`. not isAssignOp(result) ) or - exists(SubExpr sub, D::Delta d1, ConstantIntegerExpr c | + exists(SubExpr sub, QlBuiltins::BigInt d1, ConstantIntegerExpr c | result = sub and sub.getLeftOperand() = ssaRead(v, d1) and sub.getRightOperand() = c and - delta = D::fromFloat(D::toFloat(d1) + c.getIntValue()) and + delta = d1 + c.getIntValue() and not isAssignOp(result) ) or result = v.(SsaExplicitUpdate).getDefiningExpr() and if result instanceof PostIncExpr - then delta = D::fromFloat(1) // x++ === ++x - 1 + then delta = 1.toBigInt() // x++ === ++x - 1 else if result instanceof PostDecExpr - then delta = D::fromFloat(-1) // x-- === --x + 1 - else delta = D::fromFloat(0) + then delta = -1.toBigInt() // x-- === --x + 1 + else delta = 0.toBigInt() or result.(CopyValueExpr).getOperand() = ssaRead(v, delta) } @@ -45,7 +45,7 @@ module MakeUtils { * - `isEq = false` : `v != e + delta` */ pragma[nomagic] - Guard eqFlowCond(SsaVariable v, Expr e, D::Delta delta, boolean isEq, boolean testIsTrue) { + Guard eqFlowCond(SsaVariable v, Expr e, QlBuiltins::BigInt delta, boolean isEq, boolean testIsTrue) { exists(boolean eqpolarity | result.isEquality(ssaRead(v, delta), e, eqpolarity) and (testIsTrue = true or testIsTrue = false) and @@ -60,17 +60,17 @@ module MakeUtils { /** * Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`. */ - predicate ssaUpdateStep(SsaExplicitUpdate v, Expr e, D::Delta delta) { + predicate ssaUpdateStep(SsaExplicitUpdate v, Expr e, QlBuiltins::BigInt delta) { exists(Expr defExpr | defExpr = v.getDefiningExpr() | - defExpr.(CopyValueExpr).getOperand() = e and delta = D::fromFloat(0) + defExpr.(CopyValueExpr).getOperand() = e and delta = 0.toBigInt() or - defExpr.(PostIncExpr).getOperand() = e and delta = D::fromFloat(1) + defExpr.(PostIncExpr).getOperand() = e and delta = 1.toBigInt() or - defExpr.(PreIncExpr).getOperand() = e and delta = D::fromFloat(1) + defExpr.(PreIncExpr).getOperand() = e and delta = 1.toBigInt() or - defExpr.(PostDecExpr).getOperand() = e and delta = D::fromFloat(-1) + defExpr.(PostDecExpr).getOperand() = e and delta = -1.toBigInt() or - defExpr.(PreDecExpr).getOperand() = e and delta = D::fromFloat(-1) + defExpr.(PreDecExpr).getOperand() = e and delta = -1.toBigInt() or e = defExpr and not ( @@ -80,36 +80,34 @@ module MakeUtils { defExpr instanceof PostDecExpr or defExpr instanceof PreDecExpr ) and - delta = D::fromFloat(0) + delta = 0.toBigInt() ) } /** * Holds if `e1 + delta` equals `e2`. */ - predicate valueFlowStep(Expr e2, Expr e1, D::Delta delta) { - e2.(CopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0) + predicate valueFlowStep(Expr e2, Expr e1, QlBuiltins::BigInt delta) { + e2.(CopyValueExpr).getOperand() = e1 and delta = 0.toBigInt() or - e2.(PostIncExpr).getOperand() = e1 and delta = D::fromFloat(0) + e2.(PostIncExpr).getOperand() = e1 and delta = 0.toBigInt() or - e2.(PostDecExpr).getOperand() = e1 and delta = D::fromFloat(0) + e2.(PostDecExpr).getOperand() = e1 and delta = 0.toBigInt() or - e2.(PreIncExpr).getOperand() = e1 and delta = D::fromFloat(1) + e2.(PreIncExpr).getOperand() = e1 and delta = 1.toBigInt() or - e2.(PreDecExpr).getOperand() = e1 and delta = D::fromFloat(-1) + e2.(PreDecExpr).getOperand() = e1 and delta = -1.toBigInt() or - additionalValueFlowStep(e2, e1, D::toInt(delta)) + additionalValueFlowStep(e2, e1, delta) or - exists(Expr x | e2.(AddExpr).hasOperands(e1, x) | - D::fromInt(x.(ConstantIntegerExpr).getIntValue()) = delta - ) + exists(Expr x | e2.(AddExpr).hasOperands(e1, x) | x.(ConstantIntegerExpr).getIntValue() = delta) or exists(Expr x, SubExpr sub | e2 = sub and sub.getLeftOperand() = e1 and sub.getRightOperand() = x | - D::fromInt(-x.(ConstantIntegerExpr).getIntValue()) = delta + -x.(ConstantIntegerExpr).getIntValue() = delta ) }