Repository navigation
Expand file tree
/
Copy pathRangeUtils.qll
More file actions
176 lines (151 loc) · 4.98 KB
/
Copy pathRangeUtils.qll
File metadata and controls
176 lines (151 loc) · 4.98 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
* Provides utility predicates for range analysis.
*/
overlay[local?]
module;
import java
private import SSA
private import semmle.code.java.controlflow.Guards
private import semmle.code.java.Constants
private import semmle.code.java.dataflow.RangeAnalysis
private import codeql.rangeanalysis.internal.RangeUtils
private module U = MakeUtils<Location, Sem, IntDelta>;
private predicate backEdge = U::backEdge/3;
predicate ssaRead = U::ssaRead/2;
predicate ssaUpdateStep = U::ssaUpdateStep/3;
predicate valueFlowStep = U::valueFlowStep/3;
predicate guardControlsSsaRead = U::guardControlsSsaRead/3;
predicate eqFlowCond = U::eqFlowCond/5;
/**
* Holds if `v` is an input to `phi` that is not along a back edge, and the
* only other input to `phi` is a `null` value.
*
* Note that the declared type of `phi` is `SsaVariable` instead of
* `SsaPhiDefinition` in order for the reflexive case of `nonNullSsaFwdStep*(..)` to
* have non-`SsaPhiDefinition` results.
*/
private predicate nonNullSsaFwdStep(SsaDefinition v, SsaDefinition phi) {
exists(SsaExplicitWrite vnull, SsaPhiDefinition phi0 | phi0 = phi |
2 = strictcount(phi0.getAnInput()) and
vnull = phi0.getAnInput() and
v = phi0.getAnInput() and
not backEdge(phi0, v, _) and
vnull != v and
vnull.getValue() instanceof NullLiteral
)
}
private predicate nonNullDefStep(Expr e1, Expr e2) {
exists(ConditionalExpr cond, boolean branch | cond = e2 |
cond.getBranchExpr(branch) = e1 and
cond.getBranchExpr(branch.booleanNot()) instanceof NullLiteral
)
}
/**
* Gets the definition of `v` provided that `v` is a non-null array with an
* explicit `ArrayCreationExpr` definition and that the definition does not go
* through a back edge.
*/
ArrayCreationExpr getArrayDef(SsaDefinition v) {
exists(Expr src |
v.(SsaExplicitWrite).getValue() = src and
nonNullDefStep*(result, src)
)
or
exists(SsaDefinition mid |
result = getArrayDef(mid) and
nonNullSsaFwdStep(mid, v)
)
}
/**
* Holds if `arrlen` is a read of an array `length` field on an array that, if
* it is non-null, is defined by `def` and that the definition can reach
* `arrlen` without going through a back edge.
*/
private predicate arrayLengthDef(FieldRead arrlen, ArrayCreationExpr def) {
exists(SsaDefinition arr |
arrlen.getField() instanceof ArrayLengthField and
arrlen.getQualifier() = arr.getARead() and
def = getArrayDef(arr)
)
}
/** An expression that always has the same integer value. */
pragma[nomagic]
private predicate constantIntegerExpr(Expr e, int val) {
e.(CompileTimeConstantExpr).getIntValue() = val
or
e.(LongLiteral).getValue().toInt() = val
or
exists(SsaExplicitWrite v, Expr src |
e = v.getARead() and
src = v.getValue() and
constantIntegerExpr(src, val)
)
or
exists(ArrayCreationExpr a |
arrayLengthDef(e, a) and
a.getFirstDimensionSize() = val
)
or
exists(Field a, FieldRead arrlen |
a.isFinal() and
a.getInitializer().(ArrayCreationExpr).getFirstDimensionSize() = val and
arrlen.getField() instanceof ArrayLengthField and
arrlen.getQualifier() = a.getAnAccess() and
e = arrlen
)
or
CalcConstants::calculateIntValue(e) = val
}
pragma[nomagic]
private predicate constantBooleanExpr(Expr e, boolean val) {
e.(CompileTimeConstantExpr).getBooleanValue() = val
or
exists(SsaExplicitWrite v, Expr src |
e = v.getARead() and
src = v.getValue() and
constantBooleanExpr(src, val)
)
or
CalcConstants::calculateBooleanValue(e) = val
}
pragma[nomagic]
private predicate constantStringExpr(Expr e, string val) {
e.(CompileTimeConstantExpr).getStringValue() = val
or
exists(SsaExplicitWrite v, Expr src |
e = v.getARead() and
src = v.getValue() and
constantStringExpr(src, val)
)
}
private boolean getBoolValue(Expr e) { constantBooleanExpr(e, result) }
private int getIntValue(Expr e) { constantIntegerExpr(e, result) }
private module CalcConstants = CalculateConstants<getBoolValue/1, getIntValue/1>;
/** 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) }
}
/** An expression that always has the same boolean value. */
class ConstantBooleanExpr extends Expr {
ConstantBooleanExpr() { constantBooleanExpr(this, _) }
/** Gets the boolean value of this expression. */
boolean getBooleanValue() { constantBooleanExpr(this, result) }
}
/** An expression that always has the same string value. */
class ConstantStringExpr extends Expr {
ConstantStringExpr() { constantStringExpr(this, _) }
/** Get the string value of this expression. */
string getStringValue() { constantStringExpr(this, result) }
}
/**
* Holds if `e1 + delta` equals `e2`.
*/
predicate additionalValueFlowStep(Expr e2, Expr e1, int delta) {
exists(ArrayCreationExpr a |
arrayLengthDef(e2, a) and
a.getDimension(0) = e1 and
delta = 0
)
}