Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5864e57

Browse files
committed
C#: Improvements to LockOrder.ql. Detect inter-procedural locks, and tidy up the tests.
1 parent 6811d52 commit 5864e57

8 files changed

Lines changed: 169 additions & 33 deletions

File tree

csharp/ql/src/Concurrency/LockOrder.qhelp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ variables in the same sequence.</p>
1717
<p>The following example shows a program running two threads, which deadlocks because <code>thread1</code> holds <code>lock1</code> and
1818
is waiting to acquire <code>lock2</code>, whilst <code>thread2</code> holds <code>lock2</code> and is waiting to acquire <code>lock1</code>.</p>
1919

20-
<sample src="LockOrder.cs" />
20+
<sample src="LockOrderBad.cs" />
2121

2222
<p>This problem is resolved by reordering the <code>lock</code> variables as shown below.</p>
23-
<sample src="LockOrderFix.cs" />
23+
<sample src="LockOrderGood.cs" />
2424
</example>
2525

2626
<references>

csharp/ql/src/Concurrency/LockOrder.ql

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,31 @@
1313

1414
import csharp
1515

16-
from LockStmt l1, LockStmt l2, LockStmt l3, LockStmt l4, Variable v1, Variable v2
17-
where l1.getALockedStmt()=l2
18-
and l3.getALockedStmt()=l4
19-
and l1.getLockVariable()=v1
20-
and l2.getLockVariable()=v2
21-
and l3.getLockVariable()=v2
22-
and l4.getLockVariable()=v1
23-
and v1!=v2
24-
select l4, "Inconsistent lock sequence. The locks " + v1 + " and " + v2 + " are locked in a different sequence $@.",
25-
l2, "here"
16+
LockStmt getAReachableLockStmt(Callable callable) {
17+
result.getEnclosingCallable() = callable
18+
or
19+
exists(Call c | c.getEnclosingCallable() = callable |
20+
result = getAReachableLockStmt(c.getARuntimeTarget())
21+
)
22+
}
23+
24+
predicate nestedLocks(LockStmt outer, LockStmt inner) {
25+
inner = outer.getALockedStmt()
26+
or
27+
exists(Call call | call.getEnclosingStmt() = outer.getALockedStmt() |
28+
inner = getAReachableLockStmt(call.getARuntimeTarget())
29+
)
30+
}
31+
32+
from LockStmt outer1, LockStmt inner1, LockStmt outer2, LockStmt inner2, Variable v1, Variable v2
33+
where
34+
nestedLocks(outer1, inner1) and
35+
nestedLocks(outer2, inner2) and
36+
outer1.getLockVariable() = v1 and
37+
inner1.getLockVariable() = v2 and
38+
outer2.getLockVariable() = v2 and
39+
inner2.getLockVariable() = v1 and
40+
v1 != v2 and
41+
v1.getName() <= v2.getName()
42+
select inner2, "Inconsistent lock sequence. The locks " + v1 + " and " + v2 + " are locked in a different sequence $@.",
43+
inner1, "here"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System;
2+
using System.Threading;
3+
14
class Deadlock
25
{
36
private readonly Object lock1 = new Object();

csharp/ql/src/Concurrency/LockOrderFix.cs renamed to csharp/ql/src/Concurrency/LockOrderGood.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System;
2+
using System.Threading;
3+
14
class DeadlockFixed
25
{
36
private readonly Object lock1 = new Object();
Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,68 @@
11
using System;
22

3-
class Foo
3+
class LocalTest
44
{
55
Object a, b, c;
66

7-
void f()
8-
{
9-
lock (a) lock (b) { }
10-
lock (b) lock (a) { }
11-
lock (b) lock (a) { }
12-
lock (a) lock (b) { }
13-
lock (b) lock (c) { }
14-
lock (c) lock (b) { }
15-
lock (a) lock (a) { }
16-
lock (a) lock (a) { }
7+
void F()
8+
{
9+
// BAD: Flagged in G().
10+
lock (a) lock (b) lock(c) { }
11+
}
12+
13+
void G()
14+
{
15+
// BAD: Inconsistent with F().
16+
lock (a) lock (c) lock(b) { }
17+
}
18+
19+
void H()
20+
{
21+
// GOOD: Consistent with F() and G().
22+
lock (a) lock(c) { }
23+
}
24+
}
25+
26+
class GlobalTest
27+
{
28+
Object a, b, c;
29+
30+
void F()
31+
{
32+
lock (a) G();
33+
}
34+
35+
void G()
36+
{
37+
lock (b) H();
38+
lock (c) I();
39+
}
40+
41+
void H()
42+
{
43+
// BAD: Inconsistent with I().
44+
lock (c) { }
45+
}
46+
47+
void I()
48+
{
49+
// BAD: Flagged in H().
50+
lock (b) { }
1751
}
1852
}
53+
54+
class LambdaTest
55+
{
56+
Object a, b;
57+
58+
void F()
59+
{
60+
Action lock_a = () => { lock(a) { } }; // BAD: Inconsistent with lock_b.
61+
Action lock_b = () => { lock(b) { } }; // BAD: Flagged in lock_a.
62+
63+
lock(a) lock_b();
64+
lock(b) lock_a();
65+
}
66+
}
67+
68+
// semmle-extractor-options: /r:System.Runtime.Extensions.dll /r:System.Threading.dll /r:System.Threading.Thread.dll
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
| LockOrder.cs:9:18:9:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:10:18:10:29 | lock (...) {...} | here |
2-
| LockOrder.cs:9:18:9:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:11:18:11:29 | lock (...) {...} | here |
3-
| LockOrder.cs:10:18:10:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:9:18:9:29 | lock (...) {...} | here |
4-
| LockOrder.cs:10:18:10:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:12:18:12:29 | lock (...) {...} | here |
5-
| LockOrder.cs:11:18:11:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:9:18:9:29 | lock (...) {...} | here |
6-
| LockOrder.cs:11:18:11:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:12:18:12:29 | lock (...) {...} | here |
7-
| LockOrder.cs:12:18:12:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:10:18:10:29 | lock (...) {...} | here |
8-
| LockOrder.cs:12:18:12:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:11:18:11:29 | lock (...) {...} | here |
9-
| LockOrder.cs:13:18:13:29 | lock (...) {...} | Inconsistent lock sequence. The locks c and b are locked in a different sequence $@. | LockOrder.cs:14:18:14:29 | lock (...) {...} | here |
10-
| LockOrder.cs:14:18:14:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and c are locked in a different sequence $@. | LockOrder.cs:13:18:13:29 | lock (...) {...} | here |
1+
| LockOrder.cs:16:27:16:37 | lock (...) {...} | Inconsistent lock sequence. The locks b and c are locked in a different sequence $@. | LockOrder.cs:10:27:10:37 | lock (...) {...} | here |
2+
| LockOrder.cs:50:9:50:20 | lock (...) {...} | Inconsistent lock sequence. The locks b and c are locked in a different sequence $@. | LockOrder.cs:44:9:44:20 | lock (...) {...} | here |
3+
| LockOrder.cs:60:31:60:41 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:61:31:61:41 | lock (...) {...} | here |
4+
| LockOrderBad.cs:29:13:31:13 | lock (...) {...} | Inconsistent lock sequence. The locks lock1 and lock2 are locked in a different sequence $@. | LockOrderBad.cs:16:13:18:13 | lock (...) {...} | here |
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Threading;
3+
4+
class Deadlock
5+
{
6+
private readonly Object lock1 = new Object();
7+
private readonly Object lock2 = new Object();
8+
9+
public void thread1()
10+
{
11+
lock (lock1)
12+
{
13+
Console.Out.WriteLine("Thread 1 acquired lock1");
14+
Thread.Sleep(10);
15+
Console.Out.WriteLine("Thread 1 waiting on lock2");
16+
lock (lock2) // Deadlock here
17+
{
18+
}
19+
}
20+
}
21+
22+
public void thread2()
23+
{
24+
lock (lock2)
25+
{
26+
Console.Out.WriteLine("Thread 2 acquired lock2");
27+
Thread.Sleep(10);
28+
Console.Out.WriteLine("Thread 2 waiting on lock1");
29+
lock (lock1) // Deadlock here
30+
{
31+
}
32+
}
33+
}
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Threading;
3+
4+
class DeadlockFixed
5+
{
6+
private readonly Object lock1 = new Object();
7+
private readonly Object lock2 = new Object();
8+
9+
public void thread1()
10+
{
11+
lock (lock1)
12+
{
13+
Console.Out.WriteLine("Thread 1 acquired lock1");
14+
Thread.Sleep(10);
15+
Console.Out.WriteLine("Thread 1 waiting on lock2");
16+
lock (lock2)
17+
{
18+
}
19+
}
20+
}
21+
22+
public void thread2()
23+
{
24+
lock (lock1) // Fixed
25+
{
26+
Console.Out.WriteLine("Thread 2 acquired lock1");
27+
Thread.Sleep(10);
28+
Console.Out.WriteLine("Thread 2 waiting on lock2");
29+
lock (lock2) // Fixed
30+
{
31+
}
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)