Skip to content

Commit bbc0f29

Browse files
committed
Restrict getCheckedType to unrestricted records, introduce getSyntacticCheckedType and use that where appropriate
1 parent 29fdd04 commit bbc0f29

File tree

7 files changed

+27
-5
lines changed

7 files changed

+27
-5
lines changed

java/ql/lib/semmle/code/java/Dependency.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ predicate depends(RefType t, RefType dep) {
7878
// the type accessed in an `instanceof` expression in `t`.
7979
exists(InstanceOfExpr ioe | t = ioe.getEnclosingCallable().getDeclaringType() |
8080
usesType(ioe.getCheckedType(), dep)
81+
or
82+
usesType(ioe.getPattern().getAChildExpr*().getType(), dep)
8183
)
8284
or
8385
// A type accessed in a pattern-switch case statement in `t`.

java/ql/lib/semmle/code/java/DependencyCounts.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ predicate numDepends(RefType t, RefType dep, int value) {
101101
t = ioe.getEnclosingCallable().getDeclaringType()
102102
|
103103
usesType(ioe.getCheckedType(), dep)
104+
or
105+
usesType(ioe.getPattern().getAChildExpr*().getType(), dep)
104106
)
105107
or
106108
// the type accessed in a pattern-switch case statement in `t`.

java/ql/lib/semmle/code/java/Expr.qll

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1592,9 +1592,27 @@ class InstanceOfExpr extends Expr, @instanceofexpr {
15921592
/**
15931593
* Gets the type this `instanceof` expression checks for.
15941594
*
1595-
* For a match against a record pattern, this is the type of the outermost record type.
1595+
* For a match against a record pattern, this is the type of the outermost record type, and only holds if
1596+
* the record pattern matches that type unconditionally, i.e. it does not restrict field types more tightly
1597+
* than the fields' declared types and therefore match a subset of `rpe.getType()`.
15961598
*/
15971599
RefType getCheckedType() {
1600+
result = this.getTypeName().getType()
1601+
or
1602+
exists(RecordPatternExpr rpe | rpe = this.getPattern().asRecordPattern() |
1603+
result = rpe.getType() and rpe.isUnrestricted()
1604+
)
1605+
}
1606+
1607+
/**
1608+
* Gets the type this `instanceof` expression checks for.
1609+
*
1610+
* For a match against a record pattern, this is the type of the outermost record type. Note that because
1611+
* the record match might additionally constrain field or sub-record fields to have a more specific type,
1612+
* and so while if the `instanceof` test passes we know that `this.getExpr()` has this type, if it fails
1613+
* we do not know that it doesn't.
1614+
*/
1615+
RefType getSyntacticCheckedType() {
15981616
result = this.getTypeName().getType()
15991617
or
16001618
result = this.getPattern().asRecordPattern().getType()

java/ql/lib/semmle/code/java/controlflow/Guards.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ class TypeTestGuard extends Guard {
204204
TypeTestGuard() {
205205
exists(InstanceOfExpr ioe | this = ioe |
206206
testedExpr = ioe.getExpr() and
207-
testedType = ioe.getCheckedType()
207+
testedType = ioe.getSyntacticCheckedType()
208208
)
209209
or
210210
exists(PatternCase pc | this = pc |

java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ private predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) {
627627
bb.bbDominates(va.getBasicBlock()) and
628628
va = v.getAUse() and
629629
instanceofDisjunct(ioe, bb, v) and
630-
t = ioe.getCheckedType() and
630+
t = ioe.getSyntacticCheckedType() and
631631
n.asExpr() = va
632632
)
633633
}

java/ql/src/Language Abuse/DubiousTypeTestOfThis.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ from InstanceOfExpr ioe, RefType t, RefType ct
1717
where
1818
ioe.getExpr() instanceof ThisAccess and
1919
t = ioe.getExpr().getType() and
20-
ct = ioe.getCheckedType() and
20+
ct = ioe.getSyntacticCheckedType() and
2121
ct.getAnAncestor() = t
2222
select ioe,
2323
"Testing whether 'this' is an instance of $@ in $@ introduces a dependency cycle between the two types.",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ predicate instanceofInEquals(EqualsMethod m, InstanceOfExpr e) {
1818
e.getEnclosingCallable() = m and
1919
e.getExpr().(VarAccess).getVariable() = m.getParameter() and
2020
exists(RefType instanceofType |
21-
instanceofType = e.getCheckedType() and
21+
instanceofType = e.getSyntacticCheckedType() and
2222
not instanceofType.isFinal()
2323
)
2424
}

0 commit comments

Comments
 (0)