Skip to content

Commit 9dc28eb

Browse files
Merge pull request github#6387 from joefarebrother/guava-cache
Java: Model guava cache package
2 parents 763de4f + 076aeb5 commit 9dc28eb

38 files changed

+1000
-834
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 additional taint steps modeling methods in the Guava cache package (`com.google.common.cache`)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/** Flow steps through methods of `com.google.common.cache` */
2+
3+
import java
4+
private import semmle.code.java.dataflow.ExternalFlow
5+
6+
private class GuavaBaseCsv extends SummaryModelCsv {
7+
override predicate row(string row) {
8+
row =
9+
[
10+
//`namespace; type; subtypes; name; signature; ext; input; output; kind`
11+
"com.google.common.cache;Cache;true;asMap;();;MapKey of Argument[-1];MapKey of ReturnValue;value",
12+
"com.google.common.cache;Cache;true;asMap;();;MapValue of Argument[-1];MapValue of ReturnValue;value",
13+
// lambda flow from Argument[1] not implemented
14+
"com.google.common.cache;Cache;true;get;(Object,Callable);;MapValue of Argument[-1];ReturnValue;value",
15+
"com.google.common.cache;Cache;true;getIfPresent;(Object);;MapValue of Argument[-1];ReturnValue;value",
16+
// the true flow to MapKey of ReturnValue for getAllPresent is the intersection of the these inputs, but intersections cannot be modelled fully accurately.
17+
"com.google.common.cache;Cache;true;getAllPresent;(Iterable);;MapKey of Argument[-1];MapKey of ReturnValue;value",
18+
"com.google.common.cache;Cache;true;getAllPresent;(Iterable);;Element of Argument[0];MapKey of ReturnValue;value",
19+
"com.google.common.cache;Cache;true;getAllPresent;(Iterable);;MapValue of Argument[-1];MapValue of ReturnValue;value",
20+
"com.google.common.cache;Cache;true;put;(Object,Object);;Argument[0];MapKey of Argument[-1];value",
21+
"com.google.common.cache;Cache;true;put;(Object,Object);;Argument[1];MapValue of Argument[-1];value",
22+
"com.google.common.cache;Cache;true;putAll;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value",
23+
"com.google.common.cache;Cache;true;putAll;(Map);;MapValue of Argument[0];MapValue of Argument[-1];value",
24+
"com.google.common.cache;LoadingCache;true;get;(Object);;MapValue of Argument[-1];ReturnValue;value",
25+
"com.google.common.cache;LoadingCache;true;getUnchecked;(Object);;MapValue of Argument[-1];ReturnValue;value",
26+
"com.google.common.cache;LoadingCache;true;apply;(Object);;MapValue of Argument[-1];ReturnValue;value",
27+
"com.google.common.cache;LoadingCache;true;getAll;(Iterable);;Element of Argument[0];MapKey of ReturnValue;value",
28+
"com.google.common.cache;LoadingCache;true;getAll;(Iterable);;Element of Argument[0];MapKey of Argument[-1];value",
29+
"com.google.common.cache;LoadingCache;true;getAll;(Iterable);;MapValue of Argument[-1];MapValue of ReturnValue;value"
30+
]
31+
}
32+
}

java/ql/src/semmle/code/java/frameworks/guava/Guava.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ import java
66
import Base
77
import Collections
88
import IO
9+
import Cache
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package generatedtest;
2+
3+
import com.google.common.cache.Cache;
4+
import com.google.common.cache.LoadingCache;
5+
import com.google.common.cache.CacheBuilder;
6+
import com.google.common.collect.ImmutableMap;
7+
import java.util.Map;
8+
import java.util.concurrent.ConcurrentMap;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.ArrayList;
12+
13+
// Test case generated by GenerateFlowTestCase.ql
14+
public class Test {
15+
16+
<K,V> K getMapKey(Map<K,V> container) { return container.keySet().iterator().next(); }
17+
<K,V> K getMapKey(Cache<K,V> container) { return getMapKey(container.asMap()); }
18+
<K,V> V getMapValue(Map<K,V> container) { return container.values().iterator().next(); }
19+
<K,V> V getMapValue(Cache<K,V> container) { return getMapValue(container.asMap()); }
20+
<T> Iterable<T> newWithElement(T element) {
21+
List<T> l = new ArrayList();
22+
l.add(element);
23+
return l;
24+
}
25+
<K,V> Map<K,V> newMapWithMapKey(K element) {
26+
Map<K,V> m = new HashMap<K,V>();
27+
m.put(element, null);
28+
return m;
29+
}
30+
<K,V> LoadingCache<K,V> newCacheWithMapKey(K element) {
31+
LoadingCache<K,V> lc = CacheBuilder.newBuilder().build(null);
32+
lc.put(element, null);
33+
return lc;
34+
}
35+
<K,V> Map<K,V> newMapWithMapValue(V element) {
36+
Map<K,V> m = new HashMap<K,V>();
37+
m.put(null, element);
38+
return m;
39+
}
40+
<K,V> LoadingCache<K,V> newCacheWithMapValue(V element) {
41+
LoadingCache<K,V> lc = CacheBuilder.newBuilder().build(null);
42+
lc.put(null, element);
43+
return lc;
44+
}
45+
<T> T source() { return null; }
46+
void sink(Object o) { }
47+
48+
public void test() throws Exception {
49+
50+
{
51+
// "com.google.common.cache;Cache;true;asMap;();;MapKey of Argument[-1];MapKey of ReturnValue;value"
52+
ConcurrentMap out = null;
53+
LoadingCache in = newCacheWithMapKey(source());
54+
out = in.asMap();
55+
sink(getMapKey(out)); // $ hasValueFlow
56+
}
57+
{
58+
// "com.google.common.cache;Cache;true;asMap;();;MapKey of Argument[-1];MapKey of ReturnValue;value"
59+
ConcurrentMap out = null;
60+
Cache in = newCacheWithMapKey(source());
61+
out = in.asMap();
62+
sink(getMapKey(out)); // $ hasValueFlow
63+
}
64+
{
65+
// "com.google.common.cache;Cache;true;asMap;();;MapValue of Argument[-1];MapValue of ReturnValue;value"
66+
ConcurrentMap out = null;
67+
LoadingCache in = newCacheWithMapValue(source());
68+
out = in.asMap();
69+
sink(getMapValue(out)); // $ hasValueFlow
70+
}
71+
{
72+
// "com.google.common.cache;Cache;true;asMap;();;MapValue of Argument[-1];MapValue of ReturnValue;value"
73+
ConcurrentMap out = null;
74+
Cache in = newCacheWithMapValue(source());
75+
out = in.asMap();
76+
sink(getMapValue(out)); // $ hasValueFlow
77+
}
78+
{
79+
// "com.google.common.cache;Cache;true;get;(Object,Callable);;MapValue of Argument[-1];ReturnValue;value"
80+
Object out = null;
81+
Cache in = newCacheWithMapValue(source());
82+
out = in.get(null, null);
83+
sink(out); // $ hasValueFlow
84+
}
85+
{
86+
// "com.google.common.cache;Cache;true;getAllPresent;(Iterable);;Element of Argument[0];MapKey of ReturnValue;value"
87+
ImmutableMap out = null;
88+
Iterable in = newWithElement(source());
89+
Cache instance = null;
90+
out = instance.getAllPresent(in);
91+
sink(getMapKey(out)); // $ hasValueFlow
92+
}
93+
{
94+
// "com.google.common.cache;Cache;true;getAllPresent;(Iterable);;MapKey of Argument[-1];MapKey of ReturnValue;value"
95+
ImmutableMap out = null;
96+
Cache in = newCacheWithMapKey(source());
97+
out = in.getAllPresent(null);
98+
sink(getMapKey(out)); // $ hasValueFlow
99+
}
100+
{
101+
// "com.google.common.cache;Cache;true;getIfPresent;;;MapValue of Argument[-1];ReturnValue;value"
102+
Object out = null;
103+
Cache in = newCacheWithMapValue(source());
104+
out = in.getIfPresent(null);
105+
sink(out); // $ hasValueFlow
106+
}
107+
{
108+
// "com.google.common.cache;Cache;true;put;(Object,Object);;Argument[0];MapKey of Argument[-1];value"
109+
Cache out = null;
110+
Object in = source();
111+
out.put(in, null);
112+
sink(getMapKey(out)); // $ hasValueFlow
113+
}
114+
{
115+
// "com.google.common.cache;Cache;true;put;(Object,Object);;Argument[1];MapValue of Argument[-1];value"
116+
Cache out = null;
117+
Object in = source();
118+
out.put(null, in);
119+
sink(getMapValue(out)); // $ hasValueFlow
120+
}
121+
{
122+
// "com.google.common.cache;Cache;true;putAll;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value"
123+
Cache out = null;
124+
Map in = newMapWithMapKey(source());
125+
out.putAll(in);
126+
sink(getMapKey(out)); // $ hasValueFlow
127+
}
128+
{
129+
// "com.google.common.cache;Cache;true;putAll;(Map);;MapValue of Argument[0];MapValue of Argument[-1];value"
130+
Cache out = null;
131+
Map in = newMapWithMapValue(source());
132+
out.putAll(in);
133+
sink(getMapValue(out)); // $ hasValueFlow
134+
}
135+
{
136+
// "com.google.common.cache;LoadingCache;true;apply;;;MapValue of Argument[-1];ReturnValue;value"
137+
Object out = null;
138+
LoadingCache in = newCacheWithMapValue(source());
139+
out = in.apply(null);
140+
sink(out); // $ hasValueFlow
141+
}
142+
{
143+
// "com.google.common.cache;LoadingCache;true;get;;;MapValue of Argument[-1];ReturnValue;value"
144+
Object out = null;
145+
LoadingCache in = newCacheWithMapValue(source());
146+
out = in.get(null);
147+
sink(out); // $ hasValueFlow
148+
}
149+
{
150+
// "com.google.common.cache;LoadingCache;true;getAll;(Iterable);;Element of Argument[0];MapKey of Argument[-1];value"
151+
LoadingCache out = null;
152+
Iterable in = (Iterable)newWithElement(source());
153+
out.getAll(in);
154+
sink(getMapKey(out)); // $ hasValueFlow
155+
}
156+
{
157+
// "com.google.common.cache;LoadingCache;true;getAll;(Iterable);;Element of Argument[0];MapKey of ReturnValue;value"
158+
ImmutableMap out = null;
159+
Iterable in = (Iterable)newWithElement(source());
160+
LoadingCache instance = null;
161+
out = instance.getAll(in);
162+
sink(getMapKey(out)); // $ hasValueFlow
163+
}
164+
{
165+
// "com.google.common.cache;LoadingCache;true;getAll;(Iterable);;MapValue of Argument[-1];MapValue of ReturnValue;value"
166+
ImmutableMap out = null;
167+
LoadingCache in = newCacheWithMapValue(source());
168+
out = in.getAll(null);
169+
sink(getMapValue(out)); // $ hasValueFlow
170+
}
171+
{
172+
// "com.google.common.cache;LoadingCache;true;getUnchecked;;;MapValue of Argument[-1];ReturnValue;value"
173+
Object out = null;
174+
LoadingCache in = newCacheWithMapValue(source());
175+
out = in.getUnchecked(null);
176+
sink(out); // $ hasValueFlow
177+
}
178+
179+
}
180+
181+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/guava-30.0

java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected

Whitespace-only changes.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import java
2+
import semmle.code.java.dataflow.DataFlow
3+
import semmle.code.java.dataflow.ExternalFlow
4+
import semmle.code.java.dataflow.TaintTracking
5+
import TestUtilities.InlineExpectationsTest
6+
7+
class ValueFlowConf extends DataFlow::Configuration {
8+
ValueFlowConf() { this = "qltest:valueFlowConf" }
9+
10+
override predicate isSource(DataFlow::Node n) {
11+
n.asExpr().(MethodAccess).getMethod().hasName("source")
12+
}
13+
14+
override predicate isSink(DataFlow::Node n) {
15+
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
16+
}
17+
}
18+
19+
class TaintFlowConf extends TaintTracking::Configuration {
20+
TaintFlowConf() { this = "qltest:taintFlowConf" }
21+
22+
override predicate isSource(DataFlow::Node n) {
23+
n.asExpr().(MethodAccess).getMethod().hasName("source")
24+
}
25+
26+
override predicate isSink(DataFlow::Node n) {
27+
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
28+
}
29+
}
30+
31+
class HasFlowTest extends InlineExpectationsTest {
32+
HasFlowTest() { this = "HasFlowTest" }
33+
34+
override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
35+
36+
override predicate hasActualResult(Location location, string element, string tag, string value) {
37+
tag = "hasValueFlow" and
38+
exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
39+
sink.getLocation() = location and
40+
element = sink.toString() and
41+
value = ""
42+
)
43+
or
44+
tag = "hasTaintFlow" and
45+
exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf |
46+
conf.hasFlow(src, sink) and not any(ValueFlowConf c).hasFlow(src, sink)
47+
|
48+
sink.getLocation() = location and
49+
element = sink.toString() and
50+
value = ""
51+
)
52+
}
53+
}
Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,9 @@
1-
/*
2-
* Copyright (C) 2007 The Guava Authors
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5-
* in compliance with the License. You may obtain a copy of the License at
6-
*
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
*
9-
* Unless required by applicable law or agreed to in writing, software distributed under the License
10-
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11-
* or implied. See the License for the specific language governing permissions and limitations under
12-
* the License.
13-
*/
1+
// Generated automatically from com.google.common.base.Function for testing purposes, and adjusted manually
142

153
package com.google.common.base;
16-
import org.checkerframework.checker.nullness.qual.Nullable;
17-
18-
public interface Function<F, T> extends java.util.function.Function<F, T> {
19-
@Override
20-
T apply(@Nullable F input);
21-
22-
@Override
23-
boolean equals(@Nullable Object object);
244

5+
public interface Function<F, T> extends java.util.function.Function<F, T>
6+
{
7+
T apply(F p0);
8+
boolean equals(Object p0);
259
}
Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,10 @@
1-
/*
2-
* Copyright (C) 2007 The Guava Authors
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5-
* in compliance with the License. You may obtain a copy of the License at
6-
*
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
*
9-
* Unless required by applicable law or agreed to in writing, software distributed under the License
10-
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11-
* or implied. See the License for the specific language governing permissions and limitations under
12-
* the License.
13-
*/
1+
// Generated automatically from com.google.common.base.Predicate for testing purposes, and adjusted manually.
142

153
package com.google.common.base;
16-
import org.checkerframework.checker.nullness.qual.Nullable;
17-
18-
public interface Predicate<T> extends java.util.function.Predicate<T> {
19-
boolean apply(@Nullable T input);
20-
21-
@Override
22-
boolean equals(@Nullable Object object);
23-
24-
@Override
25-
default boolean test(@Nullable T input) {
26-
return false;
27-
}
284

5+
public interface Predicate<T> extends java.util.function.Predicate<T>
6+
{
7+
boolean apply(T p0);
8+
boolean equals(Object p0);
9+
default boolean test(T p0){ return false; }
2910
}
Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,8 @@
1-
/*
2-
* Copyright (C) 2007 The Guava Authors
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5-
* in compliance with the License. You may obtain a copy of the License at
6-
*
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
*
9-
* Unless required by applicable law or agreed to in writing, software distributed under the License
10-
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11-
* or implied. See the License for the specific language governing permissions and limitations under
12-
* the License.
13-
*/
1+
// Generated automatically from com.google.common.base.Supplier for testing purposes, and adjusted manually
142

153
package com.google.common.base;
164

17-
public interface Supplier<T> extends java.util.function.Supplier<T> {
18-
@Override
19-
T get();
20-
5+
public interface Supplier<T> extends java.util.function.Supplier<T>
6+
{
7+
T get();
218
}

0 commit comments

Comments
 (0)