Skip to content

Commit 5d0e727

Browse files
authored
Merge pull request #6770 from aschackmull/java/stream-model
Java: Add models for java.util.stream.
2 parents 446c738 + f885751 commit 5d0e727

File tree

8 files changed

+629
-9
lines changed

8 files changed

+629
-9
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Added data flow models for `java.util.stream.Stream`.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ private module Frameworks {
9292
private import semmle.code.java.frameworks.JsonJava
9393
private import semmle.code.java.frameworks.Objects
9494
private import semmle.code.java.frameworks.Optional
95+
private import semmle.code.java.frameworks.Stream
9596
private import semmle.code.java.frameworks.Strings
9697
private import semmle.code.java.frameworks.spring.SpringCache
9798
private import semmle.code.java.frameworks.spring.SpringHttp
@@ -574,7 +575,7 @@ module CsvValidation {
574575
not (part = "Argument" and pred = "sink") and
575576
not parseArg(part, _)
576577
or
577-
specSplit(input, part, _) and
578+
part = specLast(input) and
578579
parseParam(part, _)
579580
) and
580581
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/** Definitions related to `java.util.stream`. */
2+
3+
import semmle.code.java.dataflow.ExternalFlow
4+
5+
private class StreamModel extends SummaryModelCsv {
6+
override predicate row(string s) {
7+
s =
8+
[
9+
"java.util.stream;BaseStream;true;iterator;();;Element of Argument[-1];Element of ReturnValue;value",
10+
"java.util.stream;BaseStream;true;onClose;(Runnable);;Element of Argument[-1];Element of ReturnValue;value",
11+
"java.util.stream;BaseStream;true;parallel;();;Element of Argument[-1];Element of ReturnValue;value",
12+
"java.util.stream;BaseStream;true;sequential;();;Element of Argument[-1];Element of ReturnValue;value",
13+
"java.util.stream;BaseStream;true;spliterator;();;Element of Argument[-1];Element of ReturnValue;value",
14+
"java.util.stream;BaseStream;true;unordered;();;Element of Argument[-1];Element of ReturnValue;value",
15+
"java.util.stream;Stream;true;allMatch;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
16+
"java.util.stream;Stream;true;anyMatch;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
17+
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;ReturnValue of Argument[0];Parameter[0] of Argument[1];value",
18+
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Parameter[0] of Argument[1];ReturnValue;value",
19+
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Parameter[0] of Argument[1];Parameter[0..1] of Argument[2];value",
20+
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Parameter[0..1] of Argument[2];Parameter[0] of Argument[1];value",
21+
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Element of Argument[-1];Parameter[1] of Argument[1];value",
22+
// Missing: collect(Collector<T,A,R> collector)
23+
"java.util.stream;Stream;true;concat;(Stream,Stream);;Element of Argument[0..1];Element of ReturnValue;value",
24+
"java.util.stream;Stream;true;distinct;();;Element of Argument[-1];Element of ReturnValue;value",
25+
"java.util.stream;Stream;true;dropWhile;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
26+
"java.util.stream;Stream;true;dropWhile;(Predicate);;Element of Argument[-1];Element of ReturnValue;value",
27+
"java.util.stream;Stream;true;filter;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
28+
"java.util.stream;Stream;true;filter;(Predicate);;Element of Argument[-1];Element of ReturnValue;value",
29+
"java.util.stream;Stream;true;findAny;();;Element of Argument[-1];Element of ReturnValue;value",
30+
"java.util.stream;Stream;true;findFirst;();;Element of Argument[-1];Element of ReturnValue;value",
31+
"java.util.stream;Stream;true;flatMap;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
32+
"java.util.stream;Stream;true;flatMap;(Function);;Element of ReturnValue of Argument[0];Element of ReturnValue;value",
33+
"java.util.stream;Stream;true;flatMapToDouble;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
34+
"java.util.stream;Stream;true;flatMapToInt;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
35+
"java.util.stream;Stream;true;flatMapToLong;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
36+
"java.util.stream;Stream;true;forEach;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
37+
"java.util.stream;Stream;true;forEachOrdered;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
38+
"java.util.stream;Stream;true;generate;(Supplier);;ReturnValue of Argument[0];Element of ReturnValue;value",
39+
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;Argument[0];Element of ReturnValue;value",
40+
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;Argument[0];Parameter[0] of Argument[1..2];value",
41+
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;ReturnValue of Argument[2];Element of ReturnValue;value",
42+
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;ReturnValue of Argument[2];Parameter[0] of Argument[1..2];value",
43+
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;Argument[0];Element of ReturnValue;value",
44+
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;Argument[0];Parameter[0] of Argument[1];value",
45+
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;ReturnValue of Argument[1];Element of ReturnValue;value",
46+
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;ReturnValue of Argument[1];Parameter[0] of Argument[1];value",
47+
"java.util.stream;Stream;true;limit;(long);;Element of Argument[-1];Element of ReturnValue;value",
48+
"java.util.stream;Stream;true;map;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
49+
"java.util.stream;Stream;true;map;(Function);;ReturnValue of Argument[0];Element of ReturnValue;value",
50+
// Missing for mapMulti(BiConsumer) (not currently supported):
51+
// Argument[0] of Parameter[1] of Argument[0] -> Element of Parameter[1] of Argument[0]
52+
// Element of Parameter[1] of Argument[0] -> Element of ReturnValue
53+
"java.util.stream;Stream;true;mapMulti;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
54+
"java.util.stream;Stream;true;mapMultiToDouble;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
55+
"java.util.stream;Stream;true;mapMultiToInt;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
56+
"java.util.stream;Stream;true;mapMultiToLong;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
57+
"java.util.stream;Stream;true;mapToDouble;(ToDoubleFunction);;Element of Argument[-1];Parameter[0] of Argument[0];value",
58+
"java.util.stream;Stream;true;mapToInt;(ToIntFunction);;Element of Argument[-1];Parameter[0] of Argument[0];value",
59+
"java.util.stream;Stream;true;mapToLong;(ToLongFunction);;Element of Argument[-1];Parameter[0] of Argument[0];value",
60+
"java.util.stream;Stream;true;max;(Comparator);;Element of Argument[-1];Element of ReturnValue;value",
61+
"java.util.stream;Stream;true;max;(Comparator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
62+
"java.util.stream;Stream;true;min;(Comparator);;Element of Argument[-1];Element of ReturnValue;value",
63+
"java.util.stream;Stream;true;min;(Comparator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
64+
"java.util.stream;Stream;true;noneMatch;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
65+
"java.util.stream;Stream;true;of;(Object);;Argument[0];Element of ReturnValue;value",
66+
"java.util.stream;Stream;true;of;(Object[]);;ArrayElement of Argument[0];Element of ReturnValue;value",
67+
"java.util.stream;Stream;true;ofNullable;(Object);;Argument[0];Element of ReturnValue;value",
68+
"java.util.stream;Stream;true;peek;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
69+
"java.util.stream;Stream;true;peek;(Consumer);;Element of Argument[-1];Element of ReturnValue;value",
70+
"java.util.stream;Stream;true;reduce;(BinaryOperator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
71+
"java.util.stream;Stream;true;reduce;(BinaryOperator);;Element of Argument[-1];Element of ReturnValue;value",
72+
"java.util.stream;Stream;true;reduce;(BinaryOperator);;ReturnValue of Argument[0];Parameter[0..1] of Argument[0];value",
73+
"java.util.stream;Stream;true;reduce;(BinaryOperator);;ReturnValue of Argument[0];Element of ReturnValue;value",
74+
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;Element of Argument[-1];Parameter[0..1] of Argument[1];value",
75+
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;Argument[0];Parameter[0..1] of Argument[1];value",
76+
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;Argument[0];ReturnValue;value",
77+
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;ReturnValue of Argument[1];Parameter[0..1] of Argument[1];value",
78+
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;ReturnValue of Argument[1];ReturnValue;value",
79+
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Element of Argument[-1];Parameter[1] of Argument[1];value",
80+
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];Parameter[0] of Argument[1];value",
81+
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];Parameter[0..1] of Argument[2];value",
82+
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];ReturnValue;value",
83+
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;ReturnValue of Argument[1..2];Parameter[0] of Argument[1];value",
84+
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;ReturnValue of Argument[1..2];Parameter[0..1] of Argument[2];value",
85+
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;ReturnValue of Argument[1..2];ReturnValue;value",
86+
"java.util.stream;Stream;true;skip;(long);;Element of Argument[-1];Element of ReturnValue;value",
87+
"java.util.stream;Stream;true;sorted;;;Element of Argument[-1];Element of ReturnValue;value",
88+
"java.util.stream;Stream;true;sorted;(Comparator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
89+
"java.util.stream;Stream;true;takeWhile;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
90+
"java.util.stream;Stream;true;takeWhile;(Predicate);;Element of Argument[-1];Element of ReturnValue;value",
91+
"java.util.stream;Stream;true;toArray;;;Element of Argument[-1];ArrayElement of ReturnValue;value",
92+
"java.util.stream;Stream;true;toList;();;Element of Argument[-1];Element of ReturnValue;value"
93+
]
94+
}
95+
}

java/ql/src/utils/flowtestcasegenerator/FlowTestCaseSupportMethods.qll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,22 @@ private class EnumerationGetMethod extends GetMethod {
217217
override string getCall(string arg) { result = "getElement(" + arg + ")" }
218218
}
219219

220+
private class StreamGetMethod extends GetMethod {
221+
StreamGetMethod() { this = "streamgetmethod" }
222+
223+
override predicate appliesTo(Type t, Content c) {
224+
t.(RefType).getASourceSupertype*().hasQualifiedName("java.util.stream", "BaseStream") and
225+
c instanceof CollectionContent
226+
}
227+
228+
override string getDefinition() {
229+
result = "<T> T getElement(BaseStream<T,?> s) { return s.iterator().next(); }"
230+
}
231+
232+
bindingset[arg]
233+
override string getCall(string arg) { result = "getElement(" + arg + ")" }
234+
}
235+
220236
private class OptionalGetMethod extends GetMethod {
221237
OptionalGetMethod() { this = "optionalgetmethod" }
222238

@@ -392,6 +408,20 @@ private class IteratorGenMethod extends GenMethod {
392408
override string getCall(string arg) { result = "List.of(" + arg + ").iterator()" }
393409
}
394410

411+
private class StreamGenMethod extends GenMethod {
412+
StreamGenMethod() { this = "streamgenmethod" }
413+
414+
override predicate appliesTo(Type t, Content c) {
415+
exists(GenericType op | op.hasQualifiedName("java.util.stream", ["BaseStream", "Stream"]) |
416+
op.getAParameterizedType().getASupertype*() = t
417+
) and
418+
c instanceof CollectionContent
419+
}
420+
421+
bindingset[arg]
422+
override string getCall(string arg) { result = "Stream.of(" + arg + ")" }
423+
}
424+
395425
private class OptionalGenMethod extends GenMethod {
396426
OptionalGenMethod() { this = "optionalgenmethod" }
397427

java/ql/test/TestUtilities/InlineFlowTest.qll

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ import semmle.code.java.dataflow.ExternalFlow
4343
import semmle.code.java.dataflow.TaintTracking
4444
import TestUtilities.InlineExpectationsTest
4545

46+
private predicate defaultSource(DataFlow::Node src) {
47+
src.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
48+
}
49+
4650
class DefaultValueFlowConf extends DataFlow::Configuration {
4751
DefaultValueFlowConf() { this = "qltest:defaultValueFlowConf" }
4852

49-
override predicate isSource(DataFlow::Node n) {
50-
n.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
51-
}
53+
override predicate isSource(DataFlow::Node n) { defaultSource(n) }
5254

5355
override predicate isSink(DataFlow::Node n) {
5456
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
@@ -60,9 +62,7 @@ class DefaultValueFlowConf extends DataFlow::Configuration {
6062
class DefaultTaintFlowConf extends TaintTracking::Configuration {
6163
DefaultTaintFlowConf() { this = "qltest:defaultTaintFlowConf" }
6264

63-
override predicate isSource(DataFlow::Node n) {
64-
n.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
65-
}
65+
override predicate isSource(DataFlow::Node n) { defaultSource(n) }
6666

6767
override predicate isSink(DataFlow::Node n) {
6868
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
@@ -71,6 +71,11 @@ class DefaultTaintFlowConf extends TaintTracking::Configuration {
7171
override int fieldFlowBranchLimit() { result = 1000 }
7272
}
7373

74+
private string getSourceArgString(DataFlow::Node src) {
75+
defaultSource(src) and
76+
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
77+
}
78+
7479
class InlineFlowTest extends InlineExpectationsTest {
7580
InlineFlowTest() { this = "HasFlowTest" }
7681

@@ -81,7 +86,7 @@ class InlineFlowTest extends InlineExpectationsTest {
8186
exists(DataFlow::Node src, DataFlow::Node sink | getValueFlowConfig().hasFlow(src, sink) |
8287
sink.getLocation() = location and
8388
element = sink.toString() and
84-
value = ""
89+
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
8590
)
8691
or
8792
tag = "hasTaintFlow" and
@@ -90,7 +95,7 @@ class InlineFlowTest extends InlineExpectationsTest {
9095
|
9196
sink.getLocation() = location and
9297
element = sink.toString() and
93-
value = ""
98+
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
9499
)
95100
}
96101

0 commit comments

Comments
 (0)