Skip to content

Commit 8661933

Browse files
wasm: fix infinite loop using continue in C-like for loops (#26250)
1 parent 56228f3 commit 8661933

File tree

5 files changed

+165
-13
lines changed

5 files changed

+165
-13
lines changed

vlib/v/gen/wasm/gen.v

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,26 +1093,31 @@ pub fn (mut g Gen) expr_stmt(node ast.Stmt, expected ast.Type) {
10931093

10941094
loop := g.func.c_loop([], [])
10951095
{
1096-
g.loop_breakpoint_stack << LoopBreakpoint{
1097-
c_continue: loop
1098-
c_break: block
1099-
name: node.label
1100-
}
1096+
continue_block := g.func.c_block([], [])
1097+
{
1098+
g.loop_breakpoint_stack << LoopBreakpoint{
1099+
c_continue: continue_block
1100+
c_break: block
1101+
name: node.label
1102+
}
11011103

1102-
if node.has_cond {
1103-
g.expr(node.cond, ast.bool_type)
1104-
g.func.eqz(.i32_t)
1105-
g.func.c_br_if(block) // !cond, goto end
1106-
}
1104+
if node.has_cond {
1105+
g.expr(node.cond, ast.bool_type)
1106+
g.func.eqz(.i32_t)
1107+
g.func.c_br_if(block) // !cond, goto end
1108+
}
11071109

1108-
g.expr_stmts(node.stmts, ast.void_type)
1110+
g.expr_stmts(node.stmts, ast.void_type)
1111+
1112+
g.loop_breakpoint_stack.pop()
1113+
}
1114+
g.func.c_end(continue_block)
11091115

11101116
if node.has_inc {
11111117
g.expr_stmt(node.inc, ast.void_type)
11121118
}
11131119

11141120
g.func.c_br(loop)
1115-
g.loop_breakpoint_stack.pop()
11161121
}
11171122
g.func.c_end(loop)
11181123
}

vlib/v/gen/wasm/tests/control_flow.vv

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,51 @@ fn infcfor() int {
9494
return 0
9595
}
9696

97+
fn continuecfor() int {
98+
mut val := 0
99+
100+
for i := 0; i < 10; i += 2 {
101+
if i == 6 {
102+
continue
103+
}
104+
val += i
105+
}
106+
return val
107+
}
108+
109+
fn continuecfor_multiple() int {
110+
mut val := 0
111+
112+
for i := 0; i < 10; i += 2 {
113+
if i == 6 {
114+
continue
115+
}
116+
// Two continues
117+
if i == 2 {
118+
continue
119+
}
120+
val += i
121+
}
122+
return val
123+
}
124+
125+
fn continuec_twofor_multiple() int {
126+
mut val := 0
127+
128+
for i := 0; i < 10; i += 2 {
129+
if i == 6 {
130+
continue
131+
}
132+
for j := -12; j < 10; j += 1 {
133+
if j == 6 {
134+
continue
135+
}
136+
val += i
137+
}
138+
}
139+
return val
140+
}
141+
97142
fn main() {
98143
println('--- func()')
99144
println(func(10, true))
@@ -121,4 +166,13 @@ fn main() {
121166

122167
println('--- infcfor()')
123168
println(infcfor())
169+
170+
println('--- continuecfor()')
171+
println(continuecfor())
172+
173+
println('--- continuecfor_multiple()')
174+
println(continuecfor_multiple())
175+
176+
println('--- continuec_twofor_multiple()')
177+
println(continuec_twofor_multiple())
124178
}

vlib/v/gen/wasm/tests/control_flow.vv.out

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@
1616
100
1717
99
1818
--- infcfor()
19-
10
19+
10
20+
--- continuecfor()
21+
14
22+
--- continuecfor_multiple()
23+
12
24+
--- continuec_twofor_multiple()
25+
294
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
fn labeled_break_continue_with_inc() int {
2+
// Should not infinite loop
3+
outer: for i := 4; true; i++ {
4+
for {
5+
if i < 7 {
6+
continue outer
7+
} else {
8+
break outer
9+
}
10+
}
11+
}
12+
return 0
13+
}
14+
15+
fn labeled_break_with_inc() int {
16+
mut sum := 0
17+
outer: for i := 0; i < 10; i++ {
18+
for j := 0; j < 5; j++ {
19+
sum += j
20+
if i == 3 && j == 2 {
21+
break outer
22+
}
23+
}
24+
if sum == 10 {
25+
return i
26+
}
27+
}
28+
return sum
29+
}
30+
31+
fn triple_nested_labeled_continue() (int, int) {
32+
mut val1 := 0
33+
mut val2 := 0
34+
outer: for i := 0; i < 5; i++ {
35+
middle: for j := 0; j < 3; j++ {
36+
for k := 0; k < 2; k++ {
37+
if i == 1 && j == 1 {
38+
continue outer
39+
}
40+
val2 += 1
41+
if i == 2 && j == 2 {
42+
continue middle
43+
}
44+
val1 += 1
45+
}
46+
}
47+
}
48+
return val1, val2
49+
}
50+
51+
fn labeled_continue_deep_nest() int {
52+
mut result := 0
53+
outer: for i := 0; i < 3; i++ {
54+
for j := 0; j < 2; j++ {
55+
for k := 0; k < 2; k++ {
56+
if k == 1 && i < 2 {
57+
result++
58+
continue outer
59+
}
60+
result++
61+
}
62+
}
63+
}
64+
return result
65+
}
66+
67+
fn main() {
68+
println('--- labeled_break_continue_with_inc()')
69+
println(labeled_break_continue_with_inc())
70+
println('--- labeled_break_with_inc()')
71+
println(labeled_break_with_inc())
72+
println('--- triple_nested_labeled_continue()')
73+
a, b := triple_nested_labeled_continue()
74+
println(a)
75+
println(b)
76+
println('--- labeled_continue_deep_nest()')
77+
println(labeled_continue_deep_nest())
78+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--- labeled_break_continue_with_inc()
2+
0
3+
--- labeled_break_with_inc()
4+
0
5+
--- triple_nested_labeled_continue()
6+
24
7+
25
8+
--- labeled_continue_deep_nest()
9+
8

0 commit comments

Comments
 (0)