Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C++ SimpleRangeAnalysis: BigInt rewrite experiment #16863

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
)
}

Expand All @@ -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())
}

/**
Expand Down Expand Up @@ -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)
)
)
Expand All @@ -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
Expand All @@ -92,7 +97,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
rLower <= rUpper
|
if
lLower < 0
lLower < 0.toBigInt()
or
not (
isValidShiftExprShift(rLower, this.getLeftOperand()) and
Expand All @@ -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
Expand All @@ -119,7 +127,7 @@ class ConstantRShiftExprRange extends SimpleRangeAnalysisExpr {
rLower <= rUpper
|
if
lLower < 0
lLower < 0.toBigInt()
or
not (
isValidShiftExprShift(rLower, this.getLeftOperand()) and
Expand All @@ -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())
)
}

Expand Down Expand Up @@ -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)
)
)
Expand All @@ -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
Expand All @@ -205,7 +216,7 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
rLower <= rUpper
|
if
lLower < 0
lLower < 0.toBigInt()
or
not (
isValidShiftExprShift(rLower, this.getLeftOperand()) and
Expand All @@ -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
Expand All @@ -236,7 +250,7 @@ class ConstantLShiftExprRange extends SimpleRangeAnalysisExpr {
rLower <= rUpper
|
if
lLower < 0
lLower < 0.toBigInt()
or
not (
isValidShiftExprShift(rLower, this.getLeftOperand()) and
Expand All @@ -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())
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
}
Loading
Loading