Skip to content

Commit 734fde8

Browse files
authored
checker: add fntype casting validations (#23872)
1 parent e006b65 commit 734fde8

5 files changed

Lines changed: 121 additions & 2 deletions

File tree

‎vlib/os/process_windows.c.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type FN_NTSuspendResume = fn (voidptr) u64
1414
fn ntdll_fn(name &char) FN_NTSuspendResume {
1515
ntdll := C.GetModuleHandleA(c'NTDLL')
1616
if ntdll == 0 {
17-
return FN_NTSuspendResume(0)
17+
return unsafe { FN_NTSuspendResume(0) }
1818
}
1919
the_fn := FN_NTSuspendResume(C.GetProcAddress(ntdll, voidptr(name)))
2020
return the_fn

‎vlib/v/checker/checker.v‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3593,6 +3593,25 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
35933593
|| c.file.is_translated) && !c.check_matching_function_symbols(final_from_sym, final_to_sym) {
35943594
c.error('casting a function value from one function signature, to another function signature, should be done inside `unsafe{}` blocks',
35953595
node.pos)
3596+
} else if final_to_sym.kind == .function && final_from_sym.kind != .function {
3597+
if to_type.has_flag(.option) && node.expr !is ast.None {
3598+
c.error('casting number to Option function is not allowed, only compatible function or `none`',
3599+
node.pos)
3600+
} else if !(c.inside_unsafe || c.file.is_translated) {
3601+
if node.expr is ast.IntegerLiteral {
3602+
c.warn('casting number to function value should be done inside `unsafe{}` blocks',
3603+
node.pos)
3604+
} else if node.expr is ast.Nil {
3605+
c.warn('casting `nil` to function value should be done inside `unsafe{}` blocks',
3606+
node.pos)
3607+
} else if node.expr is ast.None {
3608+
if from_type.has_flag(.option) {
3609+
c.warn('cannot pass `none` to a non Option function type', node.pos)
3610+
}
3611+
} else if final_from_sym.kind != .voidptr {
3612+
c.error('invalid casting value to function', node.pos)
3613+
}
3614+
}
35963615
}
35973616
if to_type.is_ptr() && to_sym.kind == .alias && from_sym.kind == .map {
35983617
c.error('cannot cast to alias pointer `${c.table.type_to_str(to_type)}` because `${c.table.type_to_str(from_type)}` is a value',
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
vlib/v/checker/tests/cast_fn_err.vv:24:7: warning: casting `nil` to function value should be done inside `unsafe{}` blocks
2+
22 | // wrong ones
3+
23 | _ := FnType(foo)
4+
24 | _ := FnType(nil)
5+
| ~~~~~~~~~~~
6+
25 | _ := FnType(0)
7+
26 | _ := FnType('foo')
8+
vlib/v/checker/tests/cast_fn_err.vv:25:7: warning: casting number to function value should be done inside `unsafe{}` blocks
9+
23 | _ := FnType(foo)
10+
24 | _ := FnType(nil)
11+
25 | _ := FnType(0)
12+
| ~~~~~~~~~
13+
26 | _ := FnType('foo')
14+
27 | _ := FnType(none)
15+
vlib/v/checker/tests/cast_fn_err.vv:23:7: error: casting a function value from one function signature, to another function signature, should be done inside `unsafe{}` blocks
16+
21 |
17+
22 | // wrong ones
18+
23 | _ := FnType(foo)
19+
| ~~~~~~~~~~~
20+
24 | _ := FnType(nil)
21+
25 | _ := FnType(0)
22+
vlib/v/checker/tests/cast_fn_err.vv:24:14: error: `nil` is only allowed in `unsafe` code
23+
22 | // wrong ones
24+
23 | _ := FnType(foo)
25+
24 | _ := FnType(nil)
26+
| ~~~
27+
25 | _ := FnType(0)
28+
26 | _ := FnType('foo')
29+
vlib/v/checker/tests/cast_fn_err.vv:26:7: error: invalid casting value to function
30+
24 | _ := FnType(nil)
31+
25 | _ := FnType(0)
32+
26 | _ := FnType('foo')
33+
| ~~~~~~~~~~~~~
34+
27 | _ := FnType(none)
35+
28 | _ := ?FnType(0)
36+
vlib/v/checker/tests/cast_fn_err.vv:27:7: error: cannot cast `none` to `fn () bool`
37+
25 | _ := FnType(0)
38+
26 | _ := FnType('foo')
39+
27 | _ := FnType(none)
40+
| ~~~~~~~~~~~~
41+
28 | _ := ?FnType(0)
42+
29 | _ := ?FnType(nil)
43+
vlib/v/checker/tests/cast_fn_err.vv:28:8: error: casting number to Option function is not allowed, only compatible function or `none`
44+
26 | _ := FnType('foo')
45+
27 | _ := FnType(none)
46+
28 | _ := ?FnType(0)
47+
| ~~~~~~~~~
48+
29 | _ := ?FnType(nil)
49+
30 | _ := ?FnType(foo)
50+
vlib/v/checker/tests/cast_fn_err.vv:29:15: error: `nil` is only allowed in `unsafe` code
51+
27 | _ := FnType(none)
52+
28 | _ := ?FnType(0)
53+
29 | _ := ?FnType(nil)
54+
| ~~~
55+
30 | _ := ?FnType(foo)
56+
31 | }
57+
vlib/v/checker/tests/cast_fn_err.vv:29:8: error: casting number to Option function is not allowed, only compatible function or `none`
58+
27 | _ := FnType(none)
59+
28 | _ := ?FnType(0)
60+
29 | _ := ?FnType(nil)
61+
| ~~~~~~~~~~~
62+
30 | _ := ?FnType(foo)
63+
31 | }
64+
vlib/v/checker/tests/cast_fn_err.vv:30:8: error: casting a function value from one function signature, to another function signature, should be done inside `unsafe{}` blocks
65+
28 | _ := ?FnType(0)
66+
29 | _ := ?FnType(nil)
67+
30 | _ := ?FnType(foo)
68+
| ~~~~~~~~~~~
69+
31 | }
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
type FnType = fn () bool
2+
3+
fn foo() int {
4+
return 0
5+
}
6+
7+
fn bar() bool {
8+
return true
9+
}
10+
11+
fn main() {
12+
// acceptable ones
13+
_ := unsafe { FnType(nil) }
14+
_ := unsafe { FnType(0) }
15+
_ := unsafe { FnType(foo) }
16+
_ := unsafe { FnType(bar) }
17+
_ := FnType(bar)
18+
_ := ?FnType(none)
19+
_ := ?FnType(bar)
20+
_ := unsafe { ?FnType(foo) }
21+
22+
// wrong ones
23+
_ := FnType(foo)
24+
_ := FnType(nil)
25+
_ := FnType(0)
26+
_ := FnType('foo')
27+
_ := FnType(none)
28+
_ := ?FnType(0)
29+
_ := ?FnType(nil)
30+
_ := ?FnType(foo)
31+
}

‎vlib/v/checker/tests/mut_arg_different_muls_err.vv‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub:
1616
fn window_resized(mut w &Window) {
1717
window_width, window_height := 200, 100
1818

19-
if w.resize_fn != WindowResizeFn(0) {
19+
if w.resize_fn != unsafe { WindowResizeFn(0) } {
2020
println('fn present ${window_width} ${window_height}')
2121
w.resize_fn(w, window_width, window_height)
2222
}

0 commit comments

Comments
 (0)