Skip to content

Commit bf5c529

Browse files
authored
Merge pull request github#3897 from aibaars/util-objects
Java: data flow for `java.util.Objects`
2 parents 528f250 + 72a2497 commit bf5c529

File tree

5 files changed

+56
-0
lines changed

5 files changed

+56
-0
lines changed

java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,19 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
400400
node2.asExpr().(ChooseExpr).getAResultExpr() = node1.asExpr()
401401
or
402402
node2.asExpr().(AssignExpr).getSource() = node1.asExpr()
403+
or
404+
exists(MethodAccess ma, Method m |
405+
ma = node2.asExpr() and
406+
m = ma.getMethod() and
407+
m.getDeclaringType().hasQualifiedName("java.util", "Objects") and
408+
(
409+
m.hasName(["requireNonNull", "requireNonNullElseGet"]) and node1.asExpr() = ma.getArgument(0)
410+
or
411+
m.hasName("requireNonNullElse") and node1.asExpr() = ma.getAnArgument()
412+
or
413+
m.hasName("toString") and node1.asExpr() = ma.getArgument(1)
414+
)
415+
)
403416
}
404417

405418
/**
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import java.util.Objects;
2+
3+
class ObjectsTest {
4+
public static void valueSteps() {
5+
sink(Objects.requireNonNull(source()));
6+
sink(Objects.requireNonNull(source(), "message"));
7+
sink(Objects.requireNonNull(source(), () -> "value1"));
8+
sink(Objects.requireNonNullElse(source(), source()));
9+
sink(Objects.requireNonNullElseGet(source(), () -> "value2"));
10+
sink(Objects.toString(null, source()));
11+
}
12+
private static <T> T source() { return null; }
13+
private static void sink(Object o) {}
14+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| ObjectsTest.java:5:31:5:38 | source(...) | ObjectsTest.java:5:8:5:39 | requireNonNull(...) |
2+
| ObjectsTest.java:6:31:6:38 | source(...) | ObjectsTest.java:6:8:6:50 | requireNonNull(...) |
3+
| ObjectsTest.java:7:31:7:38 | source(...) | ObjectsTest.java:7:8:7:55 | requireNonNull(...) |
4+
| ObjectsTest.java:8:35:8:42 | source(...) | ObjectsTest.java:8:8:8:53 | requireNonNullElse(...) |
5+
| ObjectsTest.java:8:45:8:52 | source(...) | ObjectsTest.java:8:8:8:53 | requireNonNullElse(...) |
6+
| ObjectsTest.java:9:38:9:45 | source(...) | ObjectsTest.java:9:8:9:62 | requireNonNullElseGet(...) |
7+
| ObjectsTest.java:10:31:10:38 | source(...) | ObjectsTest.java:10:8:10:39 | toString(...) |
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import java
2+
import semmle.code.java.dataflow.DataFlow
3+
4+
class Conf extends DataFlow::Configuration {
5+
Conf() { this = "conf" }
6+
7+
override predicate isSource(DataFlow::Node src) {
8+
src.asExpr().(MethodAccess).getMethod().hasName("source")
9+
}
10+
11+
override predicate isSink(DataFlow::Node sink) {
12+
exists(MethodAccess ma |
13+
sink.asExpr() = ma.getAnArgument() and
14+
ma.getMethod().hasName("sink")
15+
)
16+
}
17+
}
18+
19+
from Conf c, DataFlow::Node src, DataFlow::Node sink
20+
where c.hasFlow(src, sink)
21+
select src, sink
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -source 14 -target 14

0 commit comments

Comments
 (0)