Skip to content

Commit 608fa1a

Browse files
authored
Merge pull request #20910 from yoff/java/more-thread-safe-initialisers
2 parents 26bd332 + cbc0100 commit 608fa1a

File tree

4 files changed

+73
-2
lines changed

4 files changed

+73
-2
lines changed

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,23 @@ class ExposedField extends Field {
6363
not this.getType() instanceof LockType and
6464
// field is not thread-safe
6565
not isThreadSafeType(this.getType()) and
66-
not isThreadSafeType(this.getInitializer().getType()) and
66+
not isThreadSafeType(initialValue(this).getType()) and
6767
// the initializer guarantees thread safety
68-
not isThreadSafeInitializer(this.getInitializer())
68+
not isThreadSafeInitializer(initialValue(this))
6969
}
7070
}
7171

72+
/**
73+
* Gets the initial value for the field `f`.
74+
* This is either a field initializer or an assignment in a constructor.
75+
*/
76+
Expr initialValue(Field f) {
77+
result = f.getInitializer()
78+
or
79+
result = f.getAnAssignedValue() and
80+
result.getEnclosingCallable() = f.getDeclaringType().getAConstructor()
81+
}
82+
7283
/**
7384
* A field access that is exposed to potential data races.
7485
* We require the field to be in a class that is annotated as `@ThreadSafe`.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Java thread safety analysis now understands initialization to thread safe classes inside constructors.

java/ql/test/query-tests/ThreadSafe/ThreadSafe.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@
4343
| examples/Test.java:60:5:60:10 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/Test.java:60:5:60:10 | this.y | this expression |
4444
| examples/Test.java:74:5:74:10 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/Test.java:74:5:74:10 | this.y | this expression |
4545
| examples/Test.java:74:14:74:14 | y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/Test.java:74:14:74:14 | y | this expression |
46+
| examples/ThreadSafeInitializers.java:45:9:45:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/ThreadSafeInitializers.java:45:9:45:14 | this.y | this expression |
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package examples;
2+
3+
import java.util.Map;
4+
import java.util.Set;
5+
import java.util.HashMap;
6+
import java.util.Collections;
7+
import java.util.concurrent.ConcurrentHashMap;
8+
9+
@ThreadSafe
10+
public class ThreadSafeInitializers {
11+
12+
private int y;
13+
private final Map<Integer, Integer> sync_map;
14+
private final Map<Integer, Integer> sync_map_initialised = Collections.synchronizedMap(new HashMap<Integer, Integer>());
15+
16+
17+
private final Map<String, String> cmap;
18+
private final Map<String, String> cmap_initialised = new ConcurrentHashMap();
19+
private final Set<Integer> set;
20+
private final Set<Integer> set_initialised = ConcurrentHashMap.newKeySet();
21+
22+
public ThreadSafeInitializers() {
23+
sync_map = Collections.synchronizedMap(new HashMap<Integer, Integer>());
24+
cmap = new ConcurrentHashMap();
25+
set = ConcurrentHashMap.newKeySet();
26+
}
27+
28+
public void sync_map_put(Integer i, Integer v) {
29+
sync_map.put(i,v);
30+
}
31+
32+
public void sync_map_initialised_put(Integer i, Integer v) {
33+
sync_map_initialised.put(i,v);
34+
}
35+
36+
public void cmap_put(String s1, String s2) {
37+
cmap.put(s1, s2);
38+
}
39+
40+
public void cmap_initialised_put(String s1, String s2) {
41+
cmap_initialised.put(s1, s2);
42+
}
43+
44+
public void setY(int y) {
45+
this.y = y; // $ Alert
46+
}
47+
48+
public void set_add(Integer i) {
49+
set.add(i);
50+
}
51+
52+
public void set_initialised_add(Integer i) {
53+
set_initialised.add(i);
54+
}
55+
}

0 commit comments

Comments
 (0)