Skip to content

Commit 00ae5de

Browse files
author
Dave Bartolomeo
committed
Make semantic modulus analysismatch Java results
1 parent ec3e643 commit 00ae5de

4 files changed

Lines changed: 111 additions & 163 deletions

File tree

java/ql/lib/semmle/code/java/semantic/SemanticExprSpecific.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,14 @@ module SemanticExprConfig {
337337
type = getSemanticType(update.getSourceVariable().getType()) and
338338
exists(J::Expr expr | expr = update.getDefiningExpr() |
339339
(
340-
expr instanceof J::Assignment or
340+
expr instanceof J::AssignOp or
341341
expr instanceof J::PreIncExpr or
342342
expr instanceof J::PreDecExpr
343343
) and
344344
sourceExpr = getResultExpr(expr)
345345
or
346+
sourceExpr = getResultExpr(expr.(J::AssignExpr).getSource())
347+
or
346348
sourceExpr = getResultExpr(expr.(J::LocalVariableDeclExpr).getInit())
347349
or
348350
(expr instanceof J::PostIncExpr or expr instanceof J::PostDecExpr) and

java/ql/lib/semmle/code/java/semantic/analysis/ModulusAnalysis.qll

Lines changed: 80 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
private import ModulusAnalysisSpecific::Private
88
private import semmle.code.java.semantic.SemanticBound
9+
private import semmle.code.java.semantic.SemanticCFG
910
private import semmle.code.java.semantic.SemanticExpr
1011
private import semmle.code.java.semantic.SemanticGuard
1112
private import semmle.code.java.semantic.SemanticSSA
@@ -30,9 +31,9 @@ private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, Sem
3031
* `ConstantIntegerExpr`s.
3132
*/
3233
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
33-
exists(AddExpr a | a = add |
34-
larg = a.getLhs() and
35-
rarg = a.getRhs()
34+
exists(SemAddExpr a | a = add |
35+
larg = a.getLeftOperand() and
36+
rarg = a.getRightOperand()
3637
) and
3738
not larg instanceof SemConstantIntegerExpr and
3839
not rarg instanceof SemConstantIntegerExpr
@@ -43,9 +44,9 @@ private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
4344
* a `ConstantIntegerExpr`.
4445
*/
4546
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
46-
exists(SubExpr s | s = sub |
47-
larg = s.getLhs() and
48-
rarg = s.getRhs()
47+
exists(SemSubExpr s | s = sub |
48+
larg = s.getLeftOperand() and
49+
rarg = s.getRightOperand()
4950
) and
5051
not rarg instanceof SemConstantIntegerExpr
5152
}
@@ -62,7 +63,7 @@ private SemExpr modExpr(SemExpr arg, int mod) {
6263
exists(SemConstantIntegerExpr c |
6364
mod = 2.pow([1 .. 30]) and
6465
c.getIntValue() = mod - 1 and
65-
result.(BitwiseAndExpr).hasOperands(arg, c)
66+
result.(SemBitAndExpr).hasOperands(arg, c)
6667
)
6768
}
6869

@@ -107,11 +108,11 @@ private predicate andmaskFactor(int mask, int factor) {
107108
/** Holds if `e` is evenly divisible by `factor`. */
108109
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
109110
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
110-
e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
111+
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
111112
or
112-
e.(LShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0
113+
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
113114
or
114-
e.(BitwiseAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
115+
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
115116
)
116117
}
117118

@@ -223,49 +224,54 @@ private predicate ssaModulus(SemSsaVariable v, SemSsaReadPosition pos, SemBound
223224
*/
224225
cached
225226
predicate semExprModulus(SemExpr e, SemBound b, int val, int mod) {
226-
e = b.getExpr(val) and mod = 0
227-
or
228-
evenlyDivisibleExpr(e, mod) and val = 0 and b instanceof SemZeroBound
229-
or
230-
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
231-
ssaModulus(v, bb, b, val, mod) and
232-
e = v.getAUse() and
233-
bb.getAnExpr() = e
234-
)
235-
or
236-
exists(SemExpr mid, int val0, int delta |
237-
semExprModulus(mid, b, val0, mod) and
238-
semValueFlowStep(e, mid, delta) and
239-
val = remainder(val0 + delta, mod)
240-
)
241-
or
242-
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
243-
cond = e and
244-
condExprBranchModulus(cond, true, b, v1, m1) and
245-
condExprBranchModulus(cond, false, b, v2, m2) and
246-
mod = m1.gcd(m2).gcd(v1 - v2) and
247-
mod != 1 and
248-
val = remainder(v1, mod)
249-
)
250-
or
251-
exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
252-
addModulus(e, true, b1, v1, m1) and
253-
addModulus(e, false, b2, v2, m2) and
254-
mod = m1.gcd(m2) and
255-
mod != 1 and
256-
val = remainder(v1 + v2, mod)
257-
|
258-
b = b1 and b2 instanceof SemZeroBound
227+
not ignoreExprModulus(e) and
228+
(
229+
e = b.getExpr(val) and mod = 0
259230
or
260-
b = b2 and b1 instanceof SemZeroBound
261-
)
262-
or
263-
exists(int v1, int v2, int m1, int m2 |
264-
subModulus(e, true, b, v1, m1) and
265-
subModulus(e, false, any(SemZeroBound zb), v2, m2) and
266-
mod = m1.gcd(m2) and
267-
mod != 1 and
268-
val = remainder(v1 - v2, mod)
231+
evenlyDivisibleExpr(e, mod) and
232+
val = 0 and
233+
b instanceof SemZeroBound
234+
or
235+
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
236+
ssaModulus(v, bb, b, val, mod) and
237+
e = v.getAUse() and
238+
bb.getAnExpr() = e
239+
)
240+
or
241+
exists(SemExpr mid, int val0, int delta |
242+
semExprModulus(mid, b, val0, mod) and
243+
semValueFlowStep(e, mid, delta) and
244+
val = remainder(val0 + delta, mod)
245+
)
246+
or
247+
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
248+
cond = e and
249+
condExprBranchModulus(cond, true, b, v1, m1) and
250+
condExprBranchModulus(cond, false, b, v2, m2) and
251+
mod = m1.gcd(m2).gcd(v1 - v2) and
252+
mod != 1 and
253+
val = remainder(v1, mod)
254+
)
255+
or
256+
exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
257+
addModulus(e, true, b1, v1, m1) and
258+
addModulus(e, false, b2, v2, m2) and
259+
mod = m1.gcd(m2) and
260+
mod != 1 and
261+
val = remainder(v1 + v2, mod)
262+
|
263+
b = b1 and b2 instanceof SemZeroBound
264+
or
265+
b = b2 and b1 instanceof SemZeroBound
266+
)
267+
or
268+
exists(int v1, int v2, int m1, int m2 |
269+
subModulus(e, true, b, v1, m1) and
270+
subModulus(e, false, any(SemZeroBound zb), v2, m2) and
271+
mod = m1.gcd(m2) and
272+
mod != 1 and
273+
val = remainder(v1 - v2, mod)
274+
)
269275
)
270276
}
271277

@@ -290,3 +296,25 @@ private predicate subModulus(SemExpr sub, boolean isLeft, SemBound b, int val, i
290296
semExprModulus(rarg, b, val, mod) and isLeft = false
291297
)
292298
}
299+
300+
private predicate id(SemBasicBlock x, SemBasicBlock y) { x = y }
301+
302+
private predicate idOf(SemBasicBlock x, int y) = equivalenceRelation(id/2)(x, y)
303+
304+
private int getId(SemBasicBlock bb) { idOf(bb, result) }
305+
306+
/**
307+
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
308+
* in an arbitrary 1-based numbering of the input edges to `phi`.
309+
*/
310+
private predicate rankedPhiInput(
311+
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
312+
) {
313+
edge.phiInput(phi, inp) and
314+
edge =
315+
rank[r](SemSsaReadPositionPhiInputEdge e |
316+
e.phiInput(phi, _)
317+
|
318+
e order by getId(e.getOrigBlock())
319+
)
320+
}
Lines changed: 4 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,11 @@
11
module Private {
22
private import java as J
3-
private import semmle.code.java.controlflow.BasicBlocks as BB
4-
private import semmle.code.java.semantic.SemanticCFG
53
private import semmle.code.java.semantic.SemanticExpr
6-
private import semmle.code.java.semantic.SemanticSSA
7-
8-
/** An addition or an assign-add expression. */
9-
class AddExpr extends SemExpr {
10-
AddExpr() { this instanceof SemAddExpr or this instanceof SemAssignAddExpr }
11-
12-
/** Gets the LHS operand of this add expression. */
13-
SemExpr getLhs() {
14-
result = this.(SemAddExpr).getLeftOperand()
15-
or
16-
result = this.(SemAssignAddExpr).getDest()
17-
}
18-
19-
/** Gets the RHS operand of this add expression. */
20-
SemExpr getRhs() {
21-
result = this.(SemAddExpr).getRightOperand()
22-
or
23-
result = this.(SemAssignAddExpr).getRhs()
24-
}
25-
}
26-
27-
/** A subtraction or an assign-sub expression. */
28-
class SubExpr extends SemExpr {
29-
SubExpr() { this instanceof SemSubExpr or this instanceof SemAssignSubExpr }
30-
31-
/** Gets the LHS operand of this subtraction expression. */
32-
SemExpr getLhs() {
33-
result = this.(SemSubExpr).getLeftOperand()
34-
or
35-
result = this.(SemAssignSubExpr).getDest()
36-
}
37-
38-
/** Gets the RHS operand of this subtraction expression. */
39-
SemExpr getRhs() {
40-
result = this.(SemSubExpr).getRightOperand()
41-
or
42-
result = this.(SemAssignSubExpr).getRhs()
43-
}
44-
}
45-
46-
/** A multiplication or an assign-mul expression. */
47-
class MulExpr extends SemExpr {
48-
MulExpr() { this instanceof SemMulExpr or this instanceof SemAssignMulExpr }
49-
50-
/** Gets an operand of this multiplication. */
51-
SemExpr getAnOperand() {
52-
result = this.(SemMulExpr).getAnOperand() or
53-
result = this.(SemAssignMulExpr).getSource()
54-
}
55-
}
56-
57-
/** A left shift or an assign-lshift expression. */
58-
class LShiftExpr extends SemExpr {
59-
LShiftExpr() { this instanceof SemLShiftExpr or this instanceof SemAssignLShiftExpr }
60-
61-
/** Gets the RHS operand of this shift. */
62-
SemExpr getRhs() {
63-
result = this.(SemLShiftExpr).getRightOperand() or
64-
result = this.(SemAssignLShiftExpr).getRhs()
65-
}
66-
}
67-
68-
/** A bitwise and or an assign-and expression. */
69-
class BitwiseAndExpr extends SemExpr {
70-
BitwiseAndExpr() { this instanceof SemAndBitwiseExpr or this instanceof SemAssignAndExpr }
71-
72-
/** Gets an operand of this bitwise and operation. */
73-
SemExpr getAnOperand() {
74-
result = this.(SemAndBitwiseExpr).getAnOperand() or
75-
result = this.(SemAssignAndExpr).getSource()
76-
}
77-
78-
/** Holds if this expression has operands `e1` and `e2`. */
79-
predicate hasOperands(SemExpr e1, SemExpr e2) {
80-
this.getAnOperand() = e1 and
81-
this.getAnOperand() = e2 and
82-
e1 != e2
83-
}
84-
}
85-
86-
private predicate id(BB::BasicBlock x, BB::BasicBlock y) { x = y }
87-
88-
private predicate idOf(BB::BasicBlock x, int y) = equivalenceRelation(id/2)(x, y)
89-
90-
private int getId(BB::BasicBlock bb) { idOf(bb, result) }
4+
private import semmle.code.java.semantic.SemanticExprSpecific
915

926
/**
93-
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
94-
* in an arbitrary 1-based numbering of the input edges to `phi`.
7+
* Workaround to preserve the original Java results by ignoring the modulus of
8+
* certain expressions.
959
*/
96-
predicate rankedPhiInput(
97-
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
98-
) {
99-
edge.phiInput(phi, inp) and
100-
edge =
101-
rank[r](SemSsaReadPositionPhiInputEdge e |
102-
e.phiInput(phi, _)
103-
|
104-
e order by getId(getJavaBasicBlock(e.getOrigBlock()))
105-
)
106-
}
10+
predicate ignoreExprModulus(SemExpr e) { getJavaExpr(e) instanceof J::LocalVariableDeclExpr }
10711
}

java/ql/test/library-tests/dataflow/modulus-analysis/diff.ql

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,30 @@ import java
22
import semmle.code.java.semantic.analysis.ModulusAnalysis
33
import semmle.code.java.semantic.SemanticBound
44
import semmle.code.java.semantic.SemanticExpr
5+
import semmle.code.java.semantic.SemanticExprSpecific
6+
import semmle.code.java.semantic.SemanticSSA
57
import semmle.code.java.dataflow.ModulusAnalysis
68
import semmle.code.java.dataflow.Bound
9+
import semmle.code.java.dataflow.SSA
10+
import semmle.code.java.dataflow.internal.rangeanalysis.SsaReadPositionCommon
11+
import semmle.code.java.dataflow.RangeUtils as RU
712

8-
from Expr e, Bound b, int delta, int mod, string message
9-
where
10-
semExprModulus(getSemanticExpr(e), getSemanticBound(b), delta, mod) and
11-
not exprModulus(e, b, delta, mod) and
12-
message = "semantic only"
13-
or
14-
not semExprModulus(getSemanticExpr(e), getSemanticBound(b), delta, mod) and
15-
exprModulus(e, b, delta, mod) and
16-
message = "AST only"
17-
select e, b.toString(), delta, mod
13+
predicate interestingLocation(Location loc) {
14+
// loc.getFile().getBaseName() = "Utf8Test.java" and
15+
// loc.getStartLine() in [164 .. 164] and
16+
any()
17+
}
18+
19+
query predicate diff_exprModulus(Expr e, string c, Bound b, int delta, int mod, string message) {
20+
interestingLocation(e.getLocation()) and
21+
c = concat(e.getAQlClass(), ", ") and
22+
(
23+
semExprModulus(getSemanticExpr(e), getSemanticBound(b), delta, mod) and
24+
not exprModulus(e, b, delta, mod) and
25+
message = "semantic only"
26+
or
27+
not semExprModulus(getSemanticExpr(e), getSemanticBound(b), delta, mod) and
28+
exprModulus(e, getJavaBound(b), delta, mod) and
29+
message = "AST only"
30+
)
31+
}

0 commit comments

Comments
 (0)