Skip to content

Commit e91911b

Browse files
author
Paolo Tranquilli
committed
Merge branch 'main' into redsun82/cargo-upgrade
2 parents 2a29239 + c22b05a commit e91911b

File tree

4 files changed

+61
-10
lines changed

4 files changed

+61
-10
lines changed

java/ql/src/Likely Bugs/Concurrency/UnreleasedLock.ql

+22-1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,26 @@ predicate heldByCurrentThreadCheck(LockType t, BasicBlock checkblock, BasicBlock
118118
)
119119
}
120120

121+
/**
122+
* Holds if there is a variable access in `checkblock` that has `falsesucc` as the false successor.
123+
*
124+
* The variable access must have an assigned value that is a lock access on `t`, and
125+
* the true successor of `checkblock` must contain an unlock access.
126+
*/
127+
predicate variableLockStateCheck(LockType t, BasicBlock checkblock, BasicBlock falsesucc) {
128+
exists(ConditionBlock conditionBlock, VarAccess v |
129+
v.getType() instanceof BooleanType and
130+
// Ensure that a lock access is assigned to the variable
131+
v.getVariable().getAnAssignedValue() = t.getLockAccess() and
132+
// Ensure that the `true` successor of the condition block contains an unlock access
133+
conditionBlock.getTestSuccessor(true) = t.getUnlockAccess().getBasicBlock() and
134+
conditionBlock.getCondition() = v
135+
|
136+
conditionBlock.getBasicBlock() = checkblock and
137+
conditionBlock.getTestSuccessor(false) = falsesucc
138+
)
139+
}
140+
121141
/**
122142
* A control flow path from a locking call in `src` to `b` such that the number of
123143
* locks minus the number of unlocks along the way is positive and equal to `locks`.
@@ -131,8 +151,9 @@ predicate blockIsLocked(LockType t, BasicBlock src, BasicBlock b, int locks) {
131151
// The number of net locks from the `src` block to the predecessor block `pred` is `predlocks`.
132152
blockIsLocked(t, src, pred, predlocks) and
133153
// The recursive call ensures that at least one lock is held, so do not consider the false
134-
// successor of the `isHeldByCurrentThread()` check.
154+
// successor of the `isHeldByCurrentThread()` check or of `variableLockStateCheck`.
135155
not heldByCurrentThreadCheck(t, pred, b) and
156+
not variableLockStateCheck(t, pred, b) and
136157
// Count a failed lock as an unlock so the net is zero.
137158
(if failedLock(t, pred, b) then failedlock = 1 else failedlock = 0) and
138159
(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: majorAnalysis
3+
---
4+
* Updated the `java/unreleased-lock` query so that it no longer report alerts in cases where a boolean variable is used to track lock state.

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

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
| UnreleasedLock.java:40:3:40:15 | lock(...) | This lock might not be unlocked or might be locked more times than it is unlocked. |
44
| UnreleasedLock.java:50:3:50:15 | lock(...) | This lock might not be unlocked or might be locked more times than it is unlocked. |
55
| UnreleasedLock.java:72:8:72:23 | tryLock(...) | This lock might not be unlocked or might be locked more times than it is unlocked. |
6+
| UnreleasedLock.java:114:13:114:28 | tryLock(...) | This lock might not be unlocked or might be locked more times than it is unlocked. |

java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.java

+34-9
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ void lock() throws RuntimeException { }
55
void unlock() { }
66
boolean isHeldByCurrentThread() { return true; }
77
}
8-
8+
99
void f() throws RuntimeException { }
1010
void g() throws RuntimeException { }
11-
11+
1212
MyLock mylock = new MyLock();
13-
13+
1414
void bad1() {
1515
mylock.lock();
1616
f();
1717
mylock.unlock();
1818
}
19-
19+
2020
void good2() {
2121
mylock.lock();
2222
try {
@@ -25,7 +25,7 @@ void good2() {
2525
mylock.unlock();
2626
}
2727
}
28-
28+
2929
void bad3() {
3030
mylock.lock();
3131
f();
@@ -35,7 +35,7 @@ void bad3() {
3535
mylock.unlock();
3636
}
3737
}
38-
38+
3939
void bad4() {
4040
mylock.lock();
4141
try {
@@ -45,7 +45,7 @@ void bad4() {
4545
mylock.unlock();
4646
}
4747
}
48-
48+
4949
void bad5(boolean lockmore) {
5050
mylock.lock();
5151
try {
@@ -58,7 +58,7 @@ void bad5(boolean lockmore) {
5858
mylock.unlock();
5959
}
6060
}
61-
61+
6262
void good6() {
6363
if (!mylock.tryLock()) { return; }
6464
try {
@@ -67,7 +67,7 @@ void good6() {
6767
mylock.unlock();
6868
}
6969
}
70-
70+
7171
void bad7() {
7272
if (!mylock.tryLock()) { return; }
7373
f();
@@ -95,4 +95,29 @@ void good8() {
9595
mylock.unlock();
9696
}
9797
}
98+
99+
void good9() {
100+
boolean locked = false;
101+
try {
102+
locked = mylock.tryLock();
103+
if (!locked) { return; }
104+
} finally {
105+
if (locked) {
106+
mylock.unlock();
107+
}
108+
}
109+
}
110+
111+
void bad10() {
112+
boolean locked = false;
113+
try {
114+
locked = mylock.tryLock();
115+
if (!locked) { return; }
116+
} finally {
117+
if (locked) {
118+
g();
119+
mylock.unlock();
120+
}
121+
}
122+
}
98123
}

0 commit comments

Comments
 (0)