Skip to content

Commit bd6005e

Browse files
authored
checker: fix missing check for stack pointer return (fix #22726) (#22756)
* fix * test * fix
1 parent 2f8b2c5 commit bd6005e

File tree

4 files changed

+48
-3
lines changed

4 files changed

+48
-3
lines changed

vlib/v/checker/checker.v

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5310,11 +5310,14 @@ fn (mut c Checker) fail_if_stack_struct_action_outside_unsafe(mut ident ast.Iden
53105310
}
53115311
if obj.is_stack_obj && !c.inside_unsafe {
53125312
sym := c.table.sym(obj.typ.set_nr_muls(0))
5313-
if !sym.is_heap() && !c.pref.translated && !c.file.is_translated {
5314-
suggestion := if sym.kind == .struct {
5313+
is_heap := sym.is_heap()
5314+
if (!is_heap || !obj.typ.is_ptr()) && !c.pref.translated && !c.file.is_translated {
5315+
suggestion := if !is_heap && sym.kind == .struct {
53155316
'declaring `${sym.name}` as `@[heap]`'
5316-
} else {
5317+
} else if !is_heap {
53175318
'wrapping the `${sym.name}` object in a `struct` declared as `@[heap]`'
5319+
} else { // e.g. var from `for a in heap_object {`
5320+
'declaring `${ident.name}` mutable'
53185321
}
53195322
c.error('`${ident.name}` cannot be ${failed_action} outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.',
53205323
ident.pos)

vlib/v/checker/return.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
292292
mut r_expr := &node.exprs[expr_idxs[i]]
293293
if mut r_expr is ast.Ident {
294294
c.fail_if_stack_struct_action_outside_unsafe(mut r_expr, 'returned')
295+
} else if mut r_expr is ast.PrefixExpr && r_expr.op == .amp {
296+
// &var
297+
if mut r_expr.right is ast.Ident {
298+
c.fail_if_stack_struct_action_outside_unsafe(mut r_expr.right, 'returned')
299+
}
295300
}
296301
}
297302
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/return_stack_var_err.vv:26:12: error: `s` cannot be returned outside `unsafe` blocks as it might refer to an object stored on stack. Consider declaring `s` mutable.
2+
24 | for s in students {
3+
25 | if s.name == 'Amy' {
4+
26 | return &s
5+
| ^
6+
27 | }
7+
28 | }
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module main
2+
3+
@[heap]
4+
struct Student {
5+
name string
6+
age int
7+
}
8+
9+
fn main() {
10+
mut students := []Student{}
11+
students << Student{
12+
name: 'Mike'
13+
age: 16
14+
}
15+
students << Student{
16+
name: 'Amy'
17+
age: 15
18+
}
19+
20+
_ := get_amy(students) or { unsafe { nil } }
21+
}
22+
23+
fn get_amy(students []Student) ?&Student {
24+
for s in students {
25+
if s.name == 'Amy' {
26+
return &s
27+
}
28+
}
29+
return none
30+
}

0 commit comments

Comments
 (0)