Skip to content

Commit da62a04

Browse files
committed
Note that binding variables may be casting nodes
1 parent c11a260 commit da62a04

File tree

5 files changed

+76
-1
lines changed

5 files changed

+76
-1
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,18 @@ predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { compatibleTypes0(t
375375

376376
/** A node that performs a type cast. */
377377
class CastNode extends ExprNode {
378-
CastNode() { this.getExpr() instanceof CastingExpr }
378+
CastNode() {
379+
this.getExpr() instanceof CastingExpr
380+
or
381+
exists(SsaExplicitUpdate upd |
382+
upd.getDefiningExpr().(VariableAssign).getSource() =
383+
[
384+
any(SwitchStmt ss).getExpr(), any(SwitchExpr se).getExpr(),
385+
any(InstanceOfExpr ioe).getExpr()
386+
] and
387+
this.asExpr() = upd.getAFirstUse()
388+
)
389+
}
379390
}
380391

381392
private newtype TDataFlowCallable =
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
public class Test {
2+
3+
public static Object testFlowThroughSwitchStmt(String s, Integer i, boolean unknown) {
4+
Object o = unknown ? s : i;
5+
switch (o) {
6+
case Integer i2 -> { return i2; }
7+
default -> { return null; }
8+
}
9+
}
10+
11+
public static Object testFlowThroughSwitchExpr(String s, Integer i, boolean unknown) {
12+
Object o = unknown ? s : i;
13+
Integer toRet = switch (o) {
14+
case Integer i2 -> i2;
15+
default -> null;
16+
};
17+
return toRet;
18+
}
19+
20+
public static Object testFlowThroughBindingInstanceOf(String s, Integer i, boolean unknown) {
21+
Object o = unknown ? s : i;
22+
if (o instanceof Integer i2)
23+
return i2;
24+
else
25+
return null;
26+
}
27+
28+
public static <T> T source() { return null; }
29+
30+
public static void sink(Object o) { }
31+
32+
public static void test(boolean unknown, boolean unknown2) {
33+
34+
String source1 = source();
35+
Integer source2 = source();
36+
sink(testFlowThroughSwitchStmt(source1, source2, unknown));
37+
sink(testFlowThroughSwitchExpr(source1, source2, unknown));
38+
sink(testFlowThroughBindingInstanceOf(source1, source2, unknown));
39+
40+
}
41+
42+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args --release 21
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| Test.java:35:23:35:30 | source(...) | Test.java:36:10:36:61 | testFlowThroughSwitchStmt(...) |
2+
| Test.java:35:23:35:30 | source(...) | Test.java:37:10:37:61 | testFlowThroughSwitchExpr(...) |
3+
| Test.java:35:23:35:30 | source(...) | Test.java:38:10:38:68 | testFlowThroughBindingInstanceOf(...) |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import java
2+
import semmle.code.java.dataflow.DataFlow
3+
4+
module TestConfig implements DataFlow::ConfigSig {
5+
predicate isSource(DataFlow::Node source) {
6+
source.asExpr() = any(MethodCall mc | mc.getCallee().getName() = "source")
7+
}
8+
9+
predicate isSink(DataFlow::Node sink) {
10+
sink.asExpr() = any(MethodCall mc | mc.getMethod().getName() = "sink").getAnArgument()
11+
}
12+
}
13+
14+
module Flow = DataFlow::Global<TestConfig>;
15+
16+
from DataFlow::Node source, DataFlow::Node sink
17+
where Flow::flow(source, sink)
18+
select source, sink

0 commit comments

Comments
 (0)