Merge pull request #19539 from yoff/java/conflicting-access

This commit is contained in:
yoff
2025-10-28 20:37:44 +01:00
committed by GitHub
44 changed files with 1692 additions and 41 deletions

View File

@@ -0,0 +1,3 @@
| Escaping.java:3:7:3:7 | x | The class $@ is marked as thread-safe, but this field is potentially escaping. | Escaping.java:2:14:2:21 | Escaping | Escaping |
| Escaping.java:4:14:4:14 | y | The class $@ is marked as thread-safe, but this field is potentially escaping. | Escaping.java:2:14:2:21 | Escaping | Escaping |
| Escaping.java:9:18:9:18 | b | The class $@ is marked as thread-safe, but this field is potentially escaping. | Escaping.java:2:14:2:21 | Escaping | Escaping |

View File

@@ -0,0 +1,17 @@
@ThreadSafe
public class Escaping {
int x; //$ Alert
public int y = 0; //$ Alert
private int z = 3;
final int w = 0;
public final int u = 4;
private final long a = 5;
protected long b = 0; //$ Alert
protected final long c = 0L;
volatile long d = 3;
protected volatile long e = 3L;
public void methodLocal() {
int i;
}
}

View File

@@ -0,0 +1,2 @@
query: Likely Bugs/Concurrency/Escaping.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,2 @@
public @interface ThreadSafe {
}

View File

@@ -0,0 +1,7 @@
| SafePublication.java:5:9:5:9 | z | The class $@ is marked as thread-safe, but this field is not safely published. | SafePublication.java:2:14:2:28 | SafePublication | SafePublication |
| SafePublication.java:6:9:6:9 | w | The class $@ is marked as thread-safe, but this field is not safely published. | SafePublication.java:2:14:2:28 | SafePublication | SafePublication |
| SafePublication.java:7:9:7:9 | u | The class $@ is marked as thread-safe, but this field is not safely published. | SafePublication.java:2:14:2:28 | SafePublication | SafePublication |
| SafePublication.java:11:10:11:10 | d | The class $@ is marked as thread-safe, but this field is not safely published. | SafePublication.java:2:14:2:28 | SafePublication | SafePublication |
| SafePublication.java:12:10:12:10 | e | The class $@ is marked as thread-safe, but this field is not safely published. | SafePublication.java:2:14:2:28 | SafePublication | SafePublication |
| SafePublication.java:14:11:14:13 | arr | The class $@ is marked as thread-safe, but this field is not safely published. | SafePublication.java:2:14:2:28 | SafePublication | SafePublication |
| SafePublication.java:17:10:17:11 | cc | The class $@ is marked as thread-safe, but this field is not safely published. | SafePublication.java:2:14:2:28 | SafePublication | SafePublication |

View File

@@ -0,0 +1,29 @@
@ThreadSafe
public class SafePublication {
int x;
int y = 0;
int z = 3; //$ Alert
int w; //$ Alert
int u; //$ Alert
long a;
long b = 0;
long c = 0L;
long d = 3; //$ Alert
long e = 3L; //$ Alert
int[] arr = new int[3]; //$ Alert
float f = 0.0f;
double dd = 00.0d;
char cc = 'a'; //$ Alert
char ok = '\u0000';
public SafePublication(int a) {
x = 0;
w = 3; // not ok
u = a; // not ok
}
public void methodLocal() {
int i;
}
}

View File

@@ -0,0 +1,2 @@
query: Likely Bugs/Concurrency/SafePublication.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,2 @@
public @interface ThreadSafe {
}

View File

@@ -0,0 +1,45 @@
| examples/C.java:14:9:14:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:14:9:14:14 | this.y | this expression |
| examples/C.java:15:9:15:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:15:9:15:14 | this.y | this expression |
| examples/C.java:16:9:16:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:16:9:16:14 | this.y | this expression |
| examples/C.java:16:18:16:23 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:16:18:16:23 | this.y | this expression |
| examples/C.java:20:9:20:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:20:9:20:14 | this.y | this expression |
| examples/C.java:21:9:21:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:21:9:21:14 | this.y | this expression |
| examples/C.java:22:9:22:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:22:9:22:14 | this.y | this expression |
| examples/C.java:22:18:22:23 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:22:18:22:23 | this.y | this expression |
| examples/C.java:26:9:26:14 | this.y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:26:9:26:14 | this.y | this expression |
| examples/C.java:30:13:30:13 | y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:30:13:30:13 | y | this expression |
| examples/C.java:33:9:33:9 | y | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/C.java:33:9:33:9 | y | this expression |
| examples/DeepPaths.java:8:17:8:17 | y | This field is not properly synchronized in that no single monitor covers all accesses, but the class $@ is annotated as @ThreadSafe. | examples/DeepPaths.java:7:14:7:22 | DeepPaths | DeepPaths |
| examples/FaultyTurnstileExample.java:18:5:18:9 | count | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/FaultyTurnstileExample.java:18:5:18:9 | count | this expression |
| examples/FaultyTurnstileExample.java:26:15:26:19 | count | This field is not properly synchronized in that no single monitor covers all accesses, but the class $@ is annotated as @ThreadSafe. | examples/FaultyTurnstileExample.java:23:7:23:29 | FaultyTurnstileExample2 | FaultyTurnstileExample2 |
| examples/FlawedSemaphore.java:15:14:15:18 | state | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/FlawedSemaphore.java:15:14:15:18 | state | this expression |
| examples/FlawedSemaphore.java:18:7:18:11 | state | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/FlawedSemaphore.java:18:7:18:11 | state | this expression |
| examples/LockExample.java:18:15:18:20 | length | This field is not properly synchronized in that no single monitor covers all accesses, but the class $@ is annotated as @ThreadSafe. | examples/LockExample.java:14:14:14:24 | LockExample | LockExample |
| examples/LockExample.java:19:15:19:31 | notRelatedToOther | This field is not properly synchronized in that no single monitor covers all accesses, but the class $@ is annotated as @ThreadSafe. | examples/LockExample.java:14:14:14:24 | LockExample | LockExample |
| examples/LockExample.java:20:17:20:23 | content | This field is not properly synchronized in that no single monitor covers all accesses, but the class $@ is annotated as @ThreadSafe. | examples/LockExample.java:14:14:14:24 | LockExample | LockExample |
| examples/LockExample.java:44:5:44:10 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:44:5:44:10 | length | this expression |
| examples/LockExample.java:45:5:45:11 | content | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:45:5:45:11 | content | this expression |
| examples/LockExample.java:45:13:45:18 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:45:13:45:18 | length | this expression |
| examples/LockExample.java:49:5:49:10 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:49:5:49:10 | length | this expression |
| examples/LockExample.java:62:5:62:10 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:62:5:62:10 | length | this expression |
| examples/LockExample.java:65:5:65:11 | content | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:65:5:65:11 | content | this expression |
| examples/LockExample.java:65:13:65:18 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:65:13:65:18 | length | this expression |
| examples/LockExample.java:69:5:69:10 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:69:5:69:10 | length | this expression |
| examples/LockExample.java:71:5:71:11 | content | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:71:5:71:11 | content | this expression |
| examples/LockExample.java:71:13:71:18 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:71:13:71:18 | length | this expression |
| examples/LockExample.java:76:5:76:10 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:76:5:76:10 | length | this expression |
| examples/LockExample.java:79:5:79:11 | content | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:79:5:79:11 | content | this expression |
| examples/LockExample.java:79:13:79:18 | length | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:79:13:79:18 | length | this expression |
| examples/LockExample.java:112:5:112:21 | notRelatedToOther | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:112:5:112:21 | notRelatedToOther | this expression |
| examples/LockExample.java:119:5:119:21 | notRelatedToOther | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:119:5:119:21 | notRelatedToOther | this expression |
| examples/LockExample.java:124:5:124:21 | notRelatedToOther | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:124:5:124:21 | notRelatedToOther | this expression |
| examples/LockExample.java:145:5:145:21 | notRelatedToOther | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:145:5:145:21 | notRelatedToOther | this expression |
| examples/LockExample.java:153:5:153:21 | notRelatedToOther | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/LockExample.java:153:5:153:21 | notRelatedToOther | this expression |
| examples/ManyLocks.java:8:17:8:17 | y | This field is not properly synchronized in that no single monitor covers all accesses, but the class $@ is annotated as @ThreadSafe. | examples/ManyLocks.java:7:14:7:22 | ManyLocks | ManyLocks |
| examples/SyncLstExample.java:45:5:45:7 | lst | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/SyncLstExample.java:45:5:45:7 | lst | this expression |
| examples/SyncStackExample.java:37:5:37:7 | stc | This field access (publicly accessible via $@) is not protected by any monitor, but the class is annotated as @ThreadSafe. | examples/SyncStackExample.java:37:5:37:7 | stc | this expression |
| examples/SynchronizedAndLock.java:10:17:10:22 | length | This field is not properly synchronized in that no single monitor covers all accesses, but the class $@ is annotated as @ThreadSafe. | examples/SynchronizedAndLock.java:7:14:7:32 | SynchronizedAndLock | SynchronizedAndLock |
| examples/Test.java:52:5:52: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:24:5:24:18 | setYPrivate(...) | this expression |
| 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 |

View File

@@ -0,0 +1,2 @@
query: Likely Bugs/Concurrency/ThreadSafe.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,21 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class Alias {
private int y;
private final ReentrantLock lock = new ReentrantLock();
public void notMismatch() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
y = 42;
} finally {
this.lock.unlock();
}
}
}

View File

@@ -0,0 +1,14 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package examples;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
}
}

View File

@@ -0,0 +1,72 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class C {
private int y;
private Lock lock = new ReentrantLock();
private Lock lock2 = new ReentrantLock();
public void m() {
this.y = 0; // $ Alert
this.y += 1; // $ Alert
this.y = this.y - 1; // $ Alert
}
public void n4() {
this.y = 0; // $ Alert
this.y += 1; // $ Alert
this.y = this.y - 1; // $ Alert
}
public void setY(int y) {
this.y = y; // $ Alert
}
public void test() {
if (y == 0) { // $ Alert
lock.lock();
}
y = 0; // $ Alert
lock.unlock();
}
public void n() {
this.lock.lock();
this.y = 0;
this.y += 1;
this.y = this.y - 1;
this.lock.unlock();
}
public void callTestLock2() {
lock2.lock();
setY(1);
lock2.unlock();
}
public void n2() {
lock.lock();
this.y = 0;
this.y += 1;
this.y = this.y - 1;
lock.unlock();
}
public void n3() {
lock.lock();
y = 0;
y += 1;
y = y - 1;
lock.unlock();
}
public void callTest() {
lock.lock();
setY(1);
lock.unlock();
}
}

View File

@@ -0,0 +1,61 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class DeepPaths {
private int y; // $ Alert
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
private final Lock lock3 = new ReentrantLock();
public void layer1Locked() {
lock1.lock();
this.layer2Locked();
lock1.unlock();
}
private void layer2Locked() {
lock2.lock();
this.layer3Unlocked();
lock2.unlock();
}
private void layer3Locked() {
lock3.lock();
y++;
lock3.unlock();
}
public void layer1Skip() {
lock2.lock();
this.layer3Locked();
lock2.unlock();
}
public void layer1Indirect() {
this.layer2();
}
private void layer2() {
this.layer2Locked();
}
public void layer1Unlocked() {
this.layer2Unlocked();
}
private void layer2Unlocked() {
this.layer3();
}
private void layer3() {
this.layer3Locked();
}
private void layer3Unlocked() {
y++;
}
}

View File

@@ -0,0 +1,40 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
class FaultyTurnstileExample {
private Lock lock = new ReentrantLock();
private int count = 0;
public void inc() {
lock.lock();
count++; // $ MISSING: Alert
lock.unlock();
}
public void dec() {
count--; // $ Alert
}
}
@ThreadSafe
class FaultyTurnstileExample2 {
private Lock lock1 = new ReentrantLock();
private Lock lock2 = new ReentrantLock();
private int count = 0; // $ Alert
public void inc() {
lock1.lock();
count++;
lock1.unlock();
}
public void dec() {
lock2.lock();
count--;
lock2.unlock();
}
}

View File

@@ -0,0 +1,30 @@
package examples;
@ThreadSafe
public class FlawedSemaphore {
private final int capacity;
private int state;
public FlawedSemaphore(int c) {
capacity = c;
state = 0;
}
public void acquire() {
try {
while (state == capacity) { // $ Alert
this.wait();
}
state++; // $ Alert
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void release() {
synchronized (this) {
state--; // State can become negative
this.notifyAll();
}
}
}

View File

@@ -0,0 +1,51 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class LockCorrect {
private Lock lock1 = new ReentrantLock();
private int length = 0;
private int notRelatedToOther = 10;
private int[] content = new int[10];
private int thisSynchronized = 0;
public void add(int value) {
lock1.lock();
length++;
content[length] = value;
lock1.unlock();
}
public void removeCorrect() {
lock1.lock();
content[length] = 0;
length--;
lock1.unlock();
}
public void synchronizedOnLock1() {
synchronized(lock1) {
notRelatedToOther++;
}
}
public void synchronizedOnLock12() {
synchronized(lock1) {
notRelatedToOther++;
}
}
public synchronized void x() {
thisSynchronized++;
}
public void x1() {
synchronized(this) {
thisSynchronized++;
}
}
}

View File

@@ -0,0 +1,156 @@
// This example shows that we only get one alert "per concurrency problem":
// For each problematic variable, we get one alert at the earliest conflicting write.
// If the variable is involved in several different monitors, we get an alert for each monitor that
// is not correctly used.
// A single alert can have many related locations, since each conflicting access which is not
// properly synchronized is a related location.
// This leads to many lines in the .expected file.
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class LockExample {
private Lock lock1 = new ReentrantLock();
private Lock lock2 = new ReentrantLock();
private int length = 0; // $ Alert
private int notRelatedToOther = 10; // $ Alert
private int[] content = new int[10]; // $ Alert
public void add(int value) {
lock1.lock();
length++;
content[length] = value;
lock1.unlock();
}
public void removeCorrect() {
lock1.lock();
length--;
content[length] = 0;
lock1.unlock();
}
public void notTheSameLockAsAdd() { // use locks, but different ones
lock2.lock();
length--;
content[length] = 0;
lock2.unlock();
}
public void noLock() { // no locks
length--; // $ Alert
content[length] = 0; // $ Alert
}
public void fieldUpdatedOutsideOfLock() { // adjusts length without lock
length--; // $ Alert
lock1.lock();
content[length] = 0;
lock1.unlock();
}
public synchronized void synchronizedLock() { // no locks, but with synchronized
length--;
content[length] = 0;
}
public void onlyLocked() { // never unlocked, only locked
length--; // $ Alert
lock1.lock();
content[length] = 0; // $ Alert
}
public void onlyUnlocked() { // never locked, only unlocked
length--; // $ Alert
content[length] = 0; // $ Alert
lock1.unlock();
}
public void notSameLock() {
length--; // $ Alert
lock2.lock();// Not the same lock
content[length] = 0; // $ Alert
lock1.unlock();
}
public void updateCount() {
lock2.lock();
notRelatedToOther++;
lock2.unlock();
}
public void updateCountTwiceCorrect() {
lock2.lock();
notRelatedToOther++;
lock2.unlock();
lock1.lock();
notRelatedToOther++;
lock1.unlock();
}
public void updateCountTwiceDifferentLocks() {
lock2.lock();
notRelatedToOther++;
lock2.unlock();
lock1.lock();
notRelatedToOther++;
lock2.unlock();
}
public void updateCountTwiceLock() {
lock2.lock();
notRelatedToOther++;
lock2.unlock();
lock1.lock();
notRelatedToOther++; // $ Alert
}
public void updateCountTwiceUnLock() {
lock2.lock();
notRelatedToOther++;
lock2.unlock();
notRelatedToOther++; // $ Alert
lock1.unlock();
}
public void synchronizedNonRelatedOutside() {
notRelatedToOther++; // $ Alert
synchronized(this) {
length++;
}
}
public void synchronizedNonRelatedOutside2() {
int x = 0;
x++;
synchronized(this) {
length++;
}
}
public void synchronizedNonRelatedOutside3() {
synchronized(this) {
length++;
}
notRelatedToOther = 1; // $ Alert
}
public void synchronizedNonRelatedOutside4() {
synchronized(lock1) {
length++;
}
notRelatedToOther = 1; // $ Alert
}
}

View File

@@ -0,0 +1,33 @@
package examples;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class LoopyCallGraph {
private Lock lock = new ReentrantLock();
private int count = 0;
private Random random = new Random();
public void entry() {
if (random.nextBoolean()) {
increase(); // this could look like an unprotected path to a call to dec()
} else {
lock.lock();
dec();
lock.unlock();
}
}
private void increase() {
lock.lock();
count = 10;
lock.unlock();
entry(); // this could look like an unprotected path to a call to dec()
}
private void dec() {
count--;
}
}

View File

@@ -0,0 +1,37 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class ManyLocks {
private int y; // $ Alert
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
private final Lock lock3 = new ReentrantLock();
public void inc() {
lock1.lock();
lock2.lock();
y++;
lock2.unlock();
lock1.unlock();
}
public void dec() {
lock2.lock();
lock3.lock();
y--;
lock3.unlock();
lock2.unlock();
}
public void reset() {
lock1.lock();
lock3.lock();
y = 0;
lock3.unlock();
lock1.unlock();
}
}

View File

@@ -0,0 +1,47 @@
package examples;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class SyncLstExample<T> {
private Lock lock = new ReentrantLock();
private List<T> lst;
public SyncLstExample(List<T> lst) {
this.lst = lst;
}
public void add(T item) {
lock.lock();
lst.add(item);
lock.unlock();
}
public void remove(int i) {
lock.lock();
lst.remove(i);
lock.unlock();
}
}
@ThreadSafe
class FaultySyncLstExample<T> {
private Lock lock = new ReentrantLock();
private List<T> lst;
public FaultySyncLstExample(List<T> lst) {
this.lst = lst;
}
public void add(T item) {
lock.lock();
lst.add(item);
lock.unlock();
}
public void remove(int i) {
lst.remove(i); // $ Alert
}
}

View File

@@ -0,0 +1,39 @@
package examples;
import java.util.Stack;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class SyncStackExample<T> {
private Lock lock = new ReentrantLock();
private Stack<T> stc = new Stack<T>();
public void push(T item) {
lock.lock();
stc.push(item);
lock.unlock();
}
public void pop() {
lock.lock();
stc.pop();
lock.unlock();
}
}
@ThreadSafe
class FaultySyncStackExample<T> {
private Lock lock = new ReentrantLock();
private Stack<T> stc = new Stack<T>();
public void push(T item) {
lock.lock();
stc.push(item);
lock.unlock();
}
public void pop() {
stc.pop(); // $ Alert
}
}

View File

@@ -0,0 +1,21 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class SynchronizedAndLock {
private Lock lock = new ReentrantLock();
private int length = 0; // $ Alert
public void add(int value) {
lock.lock();
length++;
lock.unlock();
}
public synchronized void subtract() {
length--;
}
}

View File

@@ -0,0 +1,76 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class Test {
/**
* Escaping field due to public visibility.
*/
int publicField;
private int y;
final int immutableField = 1;
// As of the below examples with synchronized as well. Except the incorrectly placed lock.
private Lock lock = new ReentrantLock();
/**
* Calls the a method where y field escapes.
* @param y
*/
public void setYAgainInCorrect(int t) {
setYPrivate(t);
}
/**
* Locks the method where y field escapes.
* @param y
*/
public void setYAgainCorrect(int y) {
lock.lock();
setYPrivate(y);
lock.unlock();
}
/**
* No escaping y field. Locks the y before assignment.
* @param y
*/
public void setYCorrect(int y) {
lock.lock();
this.y = y;
lock.unlock();
}
/**
* No direct escaping, since it method is private. Only escaping if another public method uses this.
* @param y
*/
private void setYPrivate(int y) {
this.y = y; // $ Alert
}
/**
* Incorrectly locks y.
* @param y
*/
public void setYWrongLock(int y) {
this.y = y; // $ Alert
lock.lock();
lock.unlock();
}
public synchronized int getImmutableField() {
return immutableField;
}
public synchronized int getImmutableField2() {
return immutableField;
}
public void testMethod() {
this.y = y + 2; // $ Alert
}
}

View File

@@ -0,0 +1,22 @@
package examples;
import java.util.ArrayList;
// Note: Not marked as thread-safe
// We inherit from this in Test3Super.java
public class Test2 {
int x;
protected ArrayList<String> lst = new ArrayList<>();
public Test2() {
this.x = 0;
}
public void changeX() {
this.x = x + 1;
}
public void changeLst() {
lst.add("Hello");
}
}

View File

@@ -0,0 +1,17 @@
package examples;
@ThreadSafe
public class Test3Super extends Test2 { // We might want an alert here for the inherited unsafe methods.
public Test3Super() {
super.x = 0;
}
public void y() {
super.x = 0; //$ MISSING: Alert
}
public void yLst() {
super.lst.add("Hello!"); //$ MISSING: Alert
}
}

View File

@@ -0,0 +1,4 @@
package examples;
public @interface ThreadSafe {
}

View File

@@ -0,0 +1,23 @@
package examples;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ThreadSafe
public class TurnstileExample {
private Lock lock = new ReentrantLock();
private int count = 0;
public void inc() {
Lock l = lock;
l.lock();
count++;
l.unlock();
}
public void dec() {
lock.lock();
count--;
lock.unlock();
}
}