Skip to content

Commit afb07e0

Browse files
authored
cgen: fix deadlock when returning multiple values in lock (#14014)
1 parent 3e3b2e2 commit afb07e0

File tree

2 files changed

+30
-37
lines changed

2 files changed

+30
-37
lines changed

vlib/v/gen/c/cgen.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3902,6 +3902,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
39023902
tmpvar := g.new_tmp_var()
39033903
ret_typ := g.typ(g.unwrap_generic(g.fn_decl.return_type))
39043904
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
3905+
|| g.cur_lock.lockeds.len > 0
39053906
// handle promoting none/error/function returning 'Option'
39063907
if fn_return_is_optional {
39073908
optional_none := node.exprs[0] is ast.None

vlib/v/tests/return_in_lock_test.v

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,46 @@
1-
// vtest retry: 3
21
import time
32

43
struct AA {
54
mut:
65
b string
76
}
87

9-
const (
10-
run_time = time.millisecond * 200 // must be big enough to ensure threads have started
11-
sleep_time = time.millisecond * 250 // some tolerance added
12-
)
13-
148
fn test_return_lock() {
159
start := time.now()
1610
shared s := AA{'3'}
17-
go printer(shared s, start)
18-
go fn (shared s AA, start time.Time) {
19-
for {
20-
reader(shared s)
21-
if time.now() - start > run_time {
22-
exit(0)
23-
}
24-
}
25-
}(shared s, start)
26-
time.sleep(sleep_time)
27-
assert false
11+
reader(shared s)
12+
lock s {
13+
assert s.b == '5'
14+
s.b = '4'
15+
}
16+
rlock s {
17+
assert s.b == '4'
18+
}
2819
}
2920

30-
fn printer(shared s AA, start time.Time) {
31-
for {
32-
lock s {
33-
assert s.b in ['0', '1', '2', '3', '4', '5']
34-
}
35-
if time.now() - start > run_time {
36-
exit(0)
37-
}
21+
fn reader(shared s AA) {
22+
lock s {
23+
assert s.b == '3'
24+
s.b = '5'
25+
// this test checks if cgen unlocks the mutex here
26+
return
3827
}
3928
}
4029

41-
fn reader(shared s AA) {
42-
mut i := 0
43-
for {
44-
i++
45-
x := i.str()
46-
lock s {
47-
s.b = x
48-
if s.b == '5' {
49-
// this test checks if cgen unlocks the mutex here
50-
return
51-
}
52-
}
30+
fn test_multi_return_lock() {
31+
shared s := AA{'3'}
32+
reti, retb := printer2(shared s)
33+
lock s {
34+
assert s.b == '3'
35+
assert reti == 4
36+
assert retb == true
37+
}
38+
}
39+
40+
fn printer2(shared s AA) (int, bool) {
41+
rlock s {
42+
assert s.b == '3'
43+
return 4, true
5344
}
45+
return 5, false
5446
}

0 commit comments

Comments
 (0)