Skip to content

Commit 465a55f

Browse files
authored
Merge pull request #333 from aschackmull/java/useless-comp-concurrent
Approved by yh-semmle
2 parents 6811d52 + 6f11849 commit 465a55f

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

change-notes/1.19/analysis-java.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
|----------------------------|------------------------|------------------------------------------------------------------|
1414
| Array index out of bounds (`java/index-out-of-bounds`) | Fewer false positive results | False positives involving arrays with a length evenly divisible by 3 or some greater number and an index being increased with a similar stride length are no longer reported. |
1515
| Unreachable catch clause (`java/unreachable-catch-clause`) | Fewer false positive results | This rule now accounts for calls to generic methods that throw generic exceptions. |
16+
| Useless comparison test (`java/constant-comparison`) | Fewer false positive results | Constant comparisons guarding `java.util.ConcurrentModificationException` are no longer reported, as they are intended to always be false in the absence of API misuse. |
1617

1718
## Changes to QL libraries
1819

java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,15 @@ predicate overFlowTest(ComparisonExpr comp) {
167167
comp.getGreaterOperand().(IntegerLiteral).getIntValue() = 0
168168
}
169169

170+
predicate concurrentModificationTest(BinaryExpr test) {
171+
exists(IfStmt ifstmt, ThrowStmt throw, RefType exc |
172+
ifstmt.getCondition() = test and
173+
(ifstmt.getThen() = throw or ifstmt.getThen().(SingletonBlock).getStmt() = throw) and
174+
throw.getExpr().(ClassInstanceExpr).getConstructedType() = exc and
175+
exc.hasQualifiedName("java.util", "ConcurrentModificationException")
176+
)
177+
}
178+
170179
/**
171180
* Holds if `test` and `guard` are equality tests of the same integral variable v with constants `c1` and `c2`.
172181
*/
@@ -202,13 +211,13 @@ where
202211
)
203212
else
204213
if constCondSimple(test, _)
205-
then (
206-
constCondSimple(test, testIsTrue) and reason = "" and reasonElem = test // dummy reason element
207-
) else
214+
then constCondSimple(test, testIsTrue) and reason = "" and reasonElem = test // dummy reason element
215+
else
208216
exists(CondReason r |
209217
constCond(test, testIsTrue, r) and reason = ", because of $@" and reasonElem = r.getCond()
210218
)
211219
) and
212220
not overFlowTest(test) and
221+
not concurrentModificationTest(test) and
213222
not exists(AssertStmt assert | assert.getExpr() = test.getParent*())
214223
select test, "Test is always " + testIsTrue + reason + ".", reasonElem, "this condition"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import java.util.*;
2+
import java.util.function.*;
3+
4+
public class B {
5+
int modcount = 0;
6+
7+
int[] arr;
8+
9+
public void modify(IntUnaryOperator func) {
10+
int mc = modcount;
11+
for (int i = 0; i < arr.length; i++) {
12+
arr[i] = func.applyAsInt(arr[i]);
13+
}
14+
// Always false unless there is a call path from func.applyAsInt(..) to
15+
// this method, but should not be reported, as checks guarding
16+
// ConcurrentModificationExceptions are expected to always be false in the
17+
// absence of API misuse.
18+
if (mc != modcount)
19+
throw new ConcurrentModificationException();
20+
modcount++;
21+
}
22+
}

0 commit comments

Comments
 (0)