Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7b84f5b

Browse files
authored
Merge pull request #372 from aschackmull/java/rangeanalysis-array-phinodes
Approved by yh-semmle
2 parents 7d37cf4 + 3d81328 commit 7b84f5b

5 files changed

Lines changed: 100 additions & 26 deletions

File tree

java/ql/src/Likely Bugs/Collections/ArrayIndexOutOfBounds.ql

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import java
1515
import semmle.code.java.dataflow.SSA
16+
import semmle.code.java.dataflow.RangeUtils
1617
import semmle.code.java.dataflow.RangeAnalysis
1718

1819
/**
@@ -31,9 +32,7 @@ predicate boundedArrayAccess(ArrayAccess aa, int k) {
3132
k = delta
3233
)
3334
or
34-
exists(ArrayCreationExpr arraycreation |
35-
arraycreation = arr.(SsaExplicitUpdate).getDefiningExpr().(VariableAssign).getSource()
36-
|
35+
exists(ArrayCreationExpr arraycreation | arraycreation = getArrayDef(arr) |
3736
k = delta and
3837
arraycreation.getDimension(0) = b.getExpr()
3938
or

java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,6 @@ private predicate unequalSsa(SsaVariable v, SsaReadPosition pos, Bound b, int de
583583
)
584584
}
585585

586-
/**
587-
* Holds if `inp` is an input to `phi` along a back edge.
588-
*/
589-
private predicate backEdge(SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge) {
590-
edge.phiInput(phi, inp) and
591-
// Conservatively assume that every edge is a back edge if we don't have dominance information.
592-
(
593-
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
594-
not hasDominanceInformation(edge.getOrigBlock())
595-
)
596-
}
597-
598586
/** Weakens a delta to lie in the range `[-1..1]`. */
599587
bindingset[delta, upper]
600588
private int weakenDelta(boolean upper, int delta) {

java/ql/src/semmle/code/java/dataflow/RangeUtils.qll

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,65 @@ import java
66
private import SSA
77
private import semmle.code.java.controlflow.internal.GuardsLogic
88

9+
/**
10+
* Holds if `v` is an input to `phi` that is not along a back edge, and the
11+
* only other input to `phi` is a `null` value.
12+
*
13+
* Note that the declared type of `phi` is `SsaVariable` instead of
14+
* `SsaPhiNode` in order for the reflexive case of `nonNullSsaFwdStep*(..)` to
15+
* have non-`SsaPhiNode` results.
16+
*/
17+
private predicate nonNullSsaFwdStep(SsaVariable v, SsaVariable phi) {
18+
exists(SsaExplicitUpdate vnull, SsaPhiNode phi0 | phi0 = phi |
19+
2 = strictcount(phi0.getAPhiInput()) and
20+
vnull = phi0.getAPhiInput() and
21+
v = phi0.getAPhiInput() and
22+
not backEdge(phi0, v, _) and
23+
vnull != v and
24+
vnull.getDefiningExpr().(VariableAssign).getSource() instanceof NullLiteral
25+
)
26+
}
27+
28+
private predicate nonNullDefStep(Expr e1, Expr e2) {
29+
e2.(ParExpr).getExpr() = e1
30+
or
31+
exists(ConditionalExpr cond | cond = e2 |
32+
cond.getTrueExpr() = e1 and cond.getFalseExpr() instanceof NullLiteral
33+
or
34+
cond.getFalseExpr() = e1 and cond.getTrueExpr() instanceof NullLiteral
35+
)
36+
}
37+
38+
/**
39+
* Gets the definition of `v` provided that `v` is a non-null array with an
40+
* explicit `ArrayCreationExpr` definition and that the definition does not go
41+
* through a back edge.
42+
*/
43+
ArrayCreationExpr getArrayDef(SsaVariable v) {
44+
exists(Expr src |
45+
v.(SsaExplicitUpdate).getDefiningExpr().(VariableAssign).getSource() = src and
46+
nonNullDefStep*(result, src)
47+
)
48+
or
49+
exists(SsaVariable mid |
50+
result = getArrayDef(mid) and
51+
nonNullSsaFwdStep(mid, v)
52+
)
53+
}
54+
55+
/**
56+
* Holds if `arrlen` is a read of an array `length` field on an array that, if
57+
* it is non-null, is defined by `def` and that the definition can reach
58+
* `arrlen` without going through a back edge.
59+
*/
60+
private predicate arrayLengthDef(FieldRead arrlen, ArrayCreationExpr def) {
61+
exists(SsaVariable arr |
62+
arrlen.getField() instanceof ArrayLengthField and
63+
arrlen.getQualifier() = arr.getAUse() and
64+
def = getArrayDef(arr)
65+
)
66+
}
67+
968
/** An expression that always has the same integer value. */
1069
pragma[nomagic]
1170
private predicate constantIntegerExpr(Expr e, int val) {
@@ -17,11 +76,17 @@ private predicate constantIntegerExpr(Expr e, int val) {
1776
constantIntegerExpr(src, val)
1877
)
1978
or
20-
exists(SsaExplicitUpdate v, FieldRead arrlen |
21-
e = arrlen and
79+
exists(ArrayCreationExpr a |
80+
arrayLengthDef(e, a) and
81+
a.getFirstDimensionSize() = val
82+
)
83+
or
84+
exists(Field a, FieldRead arrlen |
85+
a.isFinal() and
86+
a.getInitializer().(ArrayCreationExpr).getFirstDimensionSize() = val and
2287
arrlen.getField() instanceof ArrayLengthField and
23-
arrlen.getQualifier() = v.getAUse() and
24-
v.getDefiningExpr().(VariableAssign).getSource().(ArrayCreationExpr).getFirstDimensionSize() = val
88+
arrlen.getQualifier() = a.getAnAccess() and
89+
e = arrlen
2590
)
2691
}
2792

@@ -122,6 +187,18 @@ class SsaReadPositionPhiInputEdge extends SsaReadPosition, TSsaReadPositionPhiIn
122187
override string toString() { result = "edge" }
123188
}
124189

190+
/**
191+
* Holds if `inp` is an input to `phi` along a back edge.
192+
*/
193+
predicate backEdge(SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge) {
194+
edge.phiInput(phi, inp) and
195+
// Conservatively assume that every edge is a back edge if we don't have dominance information.
196+
(
197+
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
198+
not hasDominanceInformation(edge.getOrigBlock())
199+
)
200+
}
201+
125202
/**
126203
* Holds if `guard` directly controls the position `controlled` with the
127204
* value `testIsTrue`.
@@ -201,11 +278,9 @@ predicate valueFlowStep(Expr e2, Expr e1, int delta) {
201278
or
202279
e2.(PreDecExpr).getExpr() = e1 and delta = -1
203280
or
204-
exists(SsaExplicitUpdate v, FieldRead arrlen |
205-
e2 = arrlen and
206-
arrlen.getField() instanceof ArrayLengthField and
207-
arrlen.getQualifier() = v.getAUse() and
208-
v.getDefiningExpr().(VariableAssign).getSource().(ArrayCreationExpr).getDimension(0) = e1 and
281+
exists(ArrayCreationExpr a |
282+
arrayLengthDef(e2, a) and
283+
a.getDimension(0) = e1 and
209284
delta = 0
210285
)
211286
or

java/ql/test/query-tests/RangeAnalysis/A.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ void m3(int[] a) {
3434
}
3535
for (int i = 0; i < arr1.length; ) {
3636
sum += arr1[i++]; // OK
37-
sum += arr1[i++]; // OK - FP
37+
sum += arr1[i++]; // OK
3838
i += 2;
3939
}
4040
for (int i = 0; i < arr2.length; ) {
@@ -162,4 +162,17 @@ void m12() {
162162
sum += b[i] + b[i + 1]; // OK
163163
}
164164
}
165+
166+
void m13(int n) {
167+
int[] a = null;
168+
if (n > 0) {
169+
a = n > 0 ? new int[3 * n] : null;
170+
}
171+
int sum;
172+
if (a != null) {
173+
for (int i = 0; i < a.length; i += 3) {
174+
sum += a[i + 2]; // OK
175+
}
176+
}
177+
}
165178
}

java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
| A.java:16:14:16:17 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
22
| A.java:23:21:23:28 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
3-
| A.java:37:14:37:22 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
43
| A.java:42:14:42:22 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
54
| A.java:46:14:46:22 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
65
| A.java:55:14:55:19 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |

0 commit comments

Comments
 (0)