-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathUselessComparisonTest.qll
More file actions
131 lines (123 loc) · 4 KB
/
UselessComparisonTest.qll
File metadata and controls
131 lines (123 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import java
import semmle.code.java.comparison.Comparison
import semmle.code.java.controlflow.Guards
import semmle.code.java.dataflow.SSA
/**
* The kind of bound that is known to hold for some variable.
*/
class BoundKind extends string {
BoundKind() { this = ["=", "!=", ">=", "<="] }
predicate isEqual() { this = "=" }
predicate isNotEqual() { this = "!=" }
predicate isLower() { this = ">=" }
predicate isUpper() { this = "<=" }
predicate providesLowerBound() { this.isEqual() or this.isLower() }
predicate providesUpperBound() { this.isEqual() or this.isUpper() }
}
/**
* The information from `s1` implies that `test` always has the value `testIsTrue`.
*/
predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
exists(
ConditionBlock cb, SsaVariable v, BinaryExpr cond, boolean condIsTrue, int k1, int k2,
CompileTimeConstantExpr c1, CompileTimeConstantExpr c2
|
s1.getCondition() = cond and
cb.getCondition() = cond and
cond.hasOperands(v.getAUse(), c1) and
c1.getIntValue() = k1 and
test.hasOperands(v.getAUse(), c2) and
c2.getIntValue() = k2 and
v.getSourceVariable().getVariable() instanceof LocalScopeVariable and
cb.controls(test.getBasicBlock(), condIsTrue) and
v.getSourceVariable().getType() instanceof IntegralType and
exists(BoundKind boundKind, int bound |
// Simple range analysis. We infer a bound based on `cond` being
// either true (`condIsTrue = true`) or false (`condIsTrue = false`).
exists(EqualityTest condeq | cond = condeq and bound = k1 |
condIsTrue = condeq.polarity() and boundKind.isEqual()
or
condIsTrue = condeq.polarity().booleanNot() and boundKind.isNotEqual()
)
or
exists(ComparisonExpr comp | comp = cond |
comp.getLesserOperand() = v.getAUse() and
(
condIsTrue = true and
boundKind.isUpper() and
(if comp.isStrict() then bound = k1 - 1 else bound = k1)
or
condIsTrue = false and
boundKind.isLower() and
(if comp.isStrict() then bound = k1 else bound = k1 + 1)
)
or
comp.getGreaterOperand() = v.getAUse() and
(
condIsTrue = true and
boundKind.isLower() and
(if comp.isStrict() then bound = k1 + 1 else bound = k1)
or
condIsTrue = false and
boundKind.isUpper() and
(if comp.isStrict() then bound = k1 else bound = k1 - 1)
)
)
|
// Given the bound we check if the `test` is either
// always true (`testIsTrue = true`) or always false (`testIsTrue = false`).
exists(EqualityTest testeq, boolean pol | testeq = test and pol = testeq.polarity() |
(
boundKind.providesLowerBound() and k2 < bound
or
boundKind.providesUpperBound() and bound < k2
or
boundKind.isNotEqual() and k2 = bound
) and
testIsTrue = pol.booleanNot()
or
boundKind.isEqual() and k2 = bound and testIsTrue = pol
)
or
exists(ComparisonExpr comp | comp = test |
comp.getLesserOperand() = v.getAUse() and
(
boundKind.providesLowerBound() and
testIsTrue = false and
(
k2 < bound
or
k2 = bound and comp.isStrict()
)
or
boundKind.providesUpperBound() and
testIsTrue = true and
(
bound < k2
or
bound = k2 and not comp.isStrict()
)
)
or
comp.getGreaterOperand() = v.getAUse() and
(
boundKind.providesLowerBound() and
testIsTrue = true and
(
k2 < bound
or
k2 = bound and not comp.isStrict()
)
or
boundKind.providesUpperBound() and
testIsTrue = false and
(
bound < k2
or
bound = k2 and comp.isStrict()
)
)
)
)
)
}