Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions java/ql/lib/semmle/code/java/ConflictingAccess.qll
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,23 @@ class ExposedField extends Field {
not this.getType() instanceof LockType and
// field is not thread-safe
not isThreadSafeType(this.getType()) and
not isThreadSafeType(this.getInitializer().getType()) and
not isThreadSafeType(initialValue(this).getType()) and
// the initializer guarantees thread safety
not isThreadSafeInitializer(this.getInitializer())
not isThreadSafeInitializer(initialValue(this))
}
}

/**
* Gets the initial value for the field `f`.
* This is either a static initializer or an assignment in a constructor.
*/
Expr initialValue(Field f) {
result = f.getInitializer()
or
result = f.getAnAssignedValue() and
result.getEnclosingCallable() = f.getDeclaringType().getAConstructor()
}

/**
* A field access that is exposed to potential data races.
* We require the field to be in a class that is annotated as `@ThreadSafe`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Java thread safety analysis now understands initialization to thread safe classes inside constructors.
1 change: 1 addition & 0 deletions java/ql/test/query-tests/ThreadSafe/ThreadSafe.expected
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@
| 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 |
| 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 |
| 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 |
| 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package examples;

import java.util.Map;
import java.util.Set;
import java.util.HashMap;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;

@ThreadSafe
public class ThreadSafeInitializers {

private int y;
private final Map<Integer, Integer> sync_map;
private final Map<Integer, Integer> sync_map_initialised = Collections.synchronizedMap(new HashMap<Integer, Integer>());


private final Map<String, String> cmap;
private final Map<String, String> cmap_initialised = new ConcurrentHashMap();
private final Set<Integer> set;
private final Set<Integer> set_initialised = ConcurrentHashMap.newKeySet();

public ThreadSafeInitializers() {
sync_map = Collections.synchronizedMap(new HashMap<Integer, Integer>());
cmap = new ConcurrentHashMap();
set = ConcurrentHashMap.newKeySet();
}

public void sync_map_put(Integer i, Integer v) {
sync_map.put(i,v);
}

public void sync_map_initialised_put(Integer i, Integer v) {
sync_map_initialised.put(i,v);
}

public void cmap_put(String s1, String s2) {
cmap.put(s1, s2);
}

public void cmap_initialised_put(String s1, String s2) {
cmap_initialised.put(s1, s2);
}

public void setY(int y) {
this.y = y; // $ Alert
}

public void set_add(Integer i) {
set.add(i);
}

public void set_initialised_add(Integer i) {
set_initialised.add(i);
}
}