Skip to content

Commit 7233ffa

Browse files
committed
Address review comments
1 parent f026d3a commit 7233ffa

File tree

2 files changed

+55
-106
lines changed

2 files changed

+55
-106
lines changed

cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/BinaryOrAssignOperation.qll

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 55 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,6 @@
11
private import cpp
22
private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr
33
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
4-
private import experimental.semmle.code.cpp.rangeanalysis.BinaryOrAssignOperation
5-
6-
/**
7-
* The current implementation for `BitwiseAndExpr` only handles cases where both operands are
8-
* either unsigned or non-negative constants. This class not only covers these cases, but also
9-
* adds support for `&` expressions between a signed integer with a non-negative range and a
10-
* non-negative constant. It also adds support for `&=` for the same set of cases as `&`.
11-
*/
12-
private class ConstantBitwiseAndExprRange extends SimpleRangeAnalysisExpr {
13-
BinaryOrAssignConstantBitwiseAndExpr e;
14-
15-
ConstantBitwiseAndExprRange() { this = e.getOperation() }
16-
17-
BinaryOrAssignConstantBitwiseAndExpr getExpr() { result = e }
18-
19-
Expr getLeftOperand() { result = e.getLeftOperand() }
20-
21-
Expr getRightOperand() { result = e.getRightOperand() }
22-
23-
override float getLowerBounds() { result = e.getLowerBounds() }
24-
25-
override float getUpperBounds() { result = e.getUpperBounds() }
26-
27-
override predicate dependsOnChild(Expr child) { child = e.getAnOperand() }
28-
}
29-
30-
private class ConstantBitwiseAndExprOp extends Expr {
31-
BinaryOrAssignConstantBitwiseAndExpr b;
32-
float lowerBound;
33-
float upperBound;
34-
35-
ConstantBitwiseAndExprOp() {
36-
this = b.getAnOperand() and
37-
lowerBound = getFullyConvertedLowerBounds(this) and
38-
upperBound = getFullyConvertedUpperBounds(this) and
39-
lowerBound <= upperBound
40-
}
41-
42-
float getLowerBound() { result = lowerBound }
43-
44-
float getUpperBound() { result = upperBound }
45-
46-
predicate hasNegativeRange() { getLowerBound() < 0 or getUpperBound() < 0 }
47-
}
484

495
/**
506
* Holds if `e` is a constant or if it is a variable with a constant value
@@ -58,32 +14,49 @@ float evaluateConstantExpr(Expr e) {
5814
)
5915
}
6016

61-
private class BinaryOrAssignConstantBitwiseAndExpr extends BinaryOrAssignOperation {
62-
BinaryOrAssignConstantBitwiseAndExpr() {
63-
(
64-
getOperation() instanceof BitwiseAndExpr
17+
/**
18+
* The current implementation for `BitwiseAndExpr` only handles cases where both operands are
19+
* either unsigned or non-negative constants. This class not only covers these cases, but also
20+
* adds support for `&` expressions between a signed integer with a non-negative range and a
21+
* non-negative constant. It also adds support for `&=` for the same set of cases as `&`.
22+
*/
23+
private class ConstantBitwiseAndExprRange extends SimpleRangeAnalysisExpr {
24+
ConstantBitwiseAndExprRange() {
25+
exists(Expr l, Expr r |
26+
l = this.(BitwiseAndExpr).getLeftOperand() and
27+
r = this.(BitwiseAndExpr).getRightOperand()
6528
or
66-
getOperation() instanceof AssignAndExpr
67-
) and
68-
// Make sure all operands and the result type are integral
69-
getOperation().getUnspecifiedType() instanceof IntegralType and
70-
getLeftOperand().getUnspecifiedType() instanceof IntegralType and
71-
getRightOperand().getUnspecifiedType() instanceof IntegralType and
72-
// No operands can be negative constants
73-
not (evaluateConstantExpr(getLeftOperand()) < 0 or evaluateConstantExpr(getRightOperand()) < 0) and
74-
// At least one operand must be a non-negative constant
75-
(evaluateConstantExpr(getLeftOperand()) >= 0 or evaluateConstantExpr(getRightOperand()) >= 0)
29+
l = this.(AssignAndExpr).getLValue() and
30+
r = this.(AssignAndExpr).getRValue()
31+
|
32+
// No operands can be negative constants
33+
not (evaluateConstantExpr(getLOp(this)) < 0 or evaluateConstantExpr(getROp(this)) < 0) and
34+
// At least one operand must be a non-negative constant
35+
(evaluateConstantExpr(getLOp(this)) >= 0 or evaluateConstantExpr(getROp(this)) >= 0)
36+
)
7637
}
7738

78-
float getLowerBounds() {
79-
// If both operands have non-negative ranges, the lower bound is zero. If an operand can have
80-
// negative values, the lower bound is unconstrained.
81-
exists(ConstantBitwiseAndExprOp l, ConstantBitwiseAndExprOp r |
82-
l = getLeftOperand() and
83-
r = getRightOperand() and
39+
Expr getLeftOperand() {
40+
result = this.(BitwiseAndExpr).getLeftOperand() or
41+
result = this.(AssignAndExpr).getLValue()
42+
}
43+
44+
Expr getRightOperand() {
45+
result = this.(BitwiseAndExpr).getRightOperand() or
46+
result = this.(AssignAndExpr).getRValue()
47+
}
48+
49+
override float getLowerBounds() {
50+
// If an operand can have negative values, the lower bound is unconstrained.
51+
// Otherwise, the lower bound is zero.
52+
exists(float lLower, float lUpper, float rLower, float rUpper |
53+
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
54+
lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and
55+
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
56+
rUpper = getFullyConvertedUpperBounds(getRightOperand()) and
8457
(
85-
(l.hasNegativeRange() or r.hasNegativeRange()) and
86-
result = exprMinVal(getOperation())
58+
(lLower < 0 or rLower < 0) and
59+
result = exprMinVal(this)
8760
or
8861
// This technically results in two lowerBounds when an operand range is negative, but
8962
// that's fine since `exprMinVal(x) <= 0`. We can't use an if statement here without
@@ -93,20 +66,27 @@ private class BinaryOrAssignConstantBitwiseAndExpr extends BinaryOrAssignOperati
9366
)
9467
}
9568

96-
float getUpperBounds() {
69+
override float getUpperBounds() {
9770
// If an operand can have negative values, the upper bound is unconstrained.
98-
// Otherwise, the upper bound is the maximum of the upper bounds of the operands
99-
exists(ConstantBitwiseAndExprOp l, ConstantBitwiseAndExprOp r |
100-
l = getLeftOperand() and
101-
r = getRightOperand() and
71+
// Otherwise, the upper bound is the minimum of the upper bounds of the operands
72+
exists(float lLower, float lUpper, float rLower, float rUpper |
73+
lLower = getFullyConvertedLowerBounds(getLeftOperand()) and
74+
lUpper = getFullyConvertedUpperBounds(getLeftOperand()) and
75+
rLower = getFullyConvertedLowerBounds(getRightOperand()) and
76+
rUpper = getFullyConvertedUpperBounds(getRightOperand()) and
10277
(
103-
(l.hasNegativeRange() or r.hasNegativeRange()) and
104-
result = exprMaxVal(getOperation())
78+
(lLower < 0 or rLower < 0) and
79+
result = exprMaxVal(this)
10580
or
10681
// This technically results in two upperBounds when an operand range is negative, but
107-
// that's fine since `exprMaxVal(b) >= result`
108-
result = r.getUpperBound().minimum(l.getUpperBound())
82+
// that's fine since `exprMaxVal(b) >= result`. We can't use an if statement here without
83+
// non-monotonic recursion issues
84+
result = rUpper.minimum(lUpper)
10985
)
11086
)
11187
}
88+
89+
override predicate dependsOnChild(Expr child) {
90+
child = getLeftOperand() or child = getRightOperand()
91+
}
11292
}

0 commit comments

Comments
 (0)