1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

all: do not allow uninitialized function pointers

This commit is contained in:
Alexander Medvednikov 2023-08-03 21:06:32 +03:00
parent 453137384e
commit 428fd7f57f
28 changed files with 110 additions and 64 deletions

View File

@ -18,9 +18,9 @@ pub mut:
description string description string
man_description string man_description string
version string version string
pre_execute FnCommandCallback pre_execute FnCommandCallback = unsafe { nil }
execute FnCommandCallback execute FnCommandCallback = unsafe { nil }
post_execute FnCommandCallback post_execute FnCommandCallback = unsafe { nil }
disable_help bool disable_help bool
disable_man bool disable_man bool
disable_version bool disable_version bool

View File

@ -4,13 +4,22 @@ module datatypes
[heap] [heap]
struct BloomFilter[T] { struct BloomFilter[T] {
hash_func fn (T) u32 // hash function, input [T] , output u32 // TODO V bug
hash_func fn (T) u32 = unsafe { nil } // hash function, input [T] , output u32
// hash_func fn (T) u32 = empty_cb // hash function, input [T] , output u32
table_size int // every entry is one-bit, packed into `table` table_size int // every entry is one-bit, packed into `table`
num_functions int // 1~16 num_functions int // 1~16
mut: mut:
table []u8 table []u8
} }
/*
TODO maybe allow pointing to generic fns?
fn empty_cb[T](x T) u32 {
panic('empty BloomFilter.hash_func callback')
}
*/
const ( const (
// Salt values(random values). These salts are XORed with the output of the hash function to give multiple unique hashes. // Salt values(random values). These salts are XORed with the output of the hash function to give multiple unique hashes.
salts = [ salts = [

View File

@ -19,7 +19,7 @@ mut:
struct EventHandler[T] { struct EventHandler[T] {
name T name T
handler EventHandlerFn handler EventHandlerFn = unsafe { nil }
receiver voidptr = unsafe { nil } receiver voidptr = unsafe { nil }
once bool once bool
} }

View File

@ -6,15 +6,15 @@ pub struct C.FONSparams {
flags char flags char
userPtr voidptr userPtr voidptr
// int (*renderCreate)(void* uptr, int width, int height) // int (*renderCreate)(void* uptr, int width, int height)
renderCreate fn (uptr voidptr, width int, height int) int renderCreate fn (uptr voidptr, width int, height int) int = unsafe { nil }
// int (*renderResize)(void* uptr, int width, int height) // int (*renderResize)(void* uptr, int width, int height)
renderResize fn (uptr voidptr, width int, height int) int renderResize fn (uptr voidptr, width int, height int) int = unsafe { nil }
// void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data) // void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data)
renderUpdate fn (uptr voidptr, rect &int, data &u8) renderUpdate fn (uptr voidptr, rect &int, data &u8) = unsafe { nil }
// void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) // void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts)
renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int) renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int) = unsafe { nil }
// void (*renderDelete)(void* uptr) // void (*renderDelete)(void* uptr)
renderDelete fn (uptr voidptr) renderDelete fn (uptr voidptr) = unsafe { nil }
} }
pub struct C.FONSquad { pub struct C.FONSquad {

View File

@ -248,7 +248,7 @@ mut:
// counters for quantifier check (repetitions) // counters for quantifier check (repetitions)
rep int rep int
// validator function pointer // validator function pointer
validator FnValidator validator FnValidator = unsafe { nil }
// groups variables // groups variables
group_neg bool // negation flag for the group, 0 => no negation > 0 => negataion group_neg bool // negation flag for the group, 0 => no negation > 0 => negataion
group_rep int // repetition of the group group_rep int // repetition of the group
@ -376,7 +376,7 @@ fn (mut re RE) reset_src() {
******************************************************************************/ ******************************************************************************/
struct BslsStruct { struct BslsStruct {
ch rune // meta char ch rune // meta char
validator FnValidator // validator function pointer validator FnValidator = unsafe { nil } // validator function pointer
} }
const ( const (
@ -463,7 +463,7 @@ mut:
cc_type int // type of cc token cc_type int // type of cc token
ch0 rune // first char of the interval a-b a in this case ch0 rune // first char of the interval a-b a in this case
ch1 rune // second char of the interval a-b b in this case ch1 rune // second char of the interval a-b b in this case
validator FnValidator // validator function pointer validator FnValidator = unsafe { nil } // validator function pointer
} }
enum CharClass_parse_state { enum CharClass_parse_state {

View File

@ -5,14 +5,14 @@ import sokol.memory
[typedef] [typedef]
pub struct C.sg_allocator { pub struct C.sg_allocator {
pub mut: pub mut:
alloc memory.FnAllocatorAlloc alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr user_data voidptr
} }
[typedef] [typedef]
pub struct C.sg_logger { pub struct C.sg_logger {
pub mut: pub mut:
log_cb memory.FnLogCb log_cb memory.FnLogCb = unsafe { nil }
user_data voidptr user_data voidptr
} }

View File

@ -46,8 +46,8 @@ pub type GLContextDesc = C.sg_gl_context_desc
struct C.sg_metal_context_desc { struct C.sg_metal_context_desc {
device voidptr device voidptr
renderpass_descriptor_cb fn () voidptr renderpass_descriptor_cb fn () voidptr = unsafe { nil }
drawable_cb fn () voidptr drawable_cb fn () voidptr = unsafe { nil }
} }
pub type MetalContextDesc = C.sg_metal_context_desc pub type MetalContextDesc = C.sg_metal_context_desc
@ -55,8 +55,8 @@ pub type MetalContextDesc = C.sg_metal_context_desc
struct C.sg_d3d11_context_desc { struct C.sg_d3d11_context_desc {
device voidptr device voidptr
device_context voidptr device_context voidptr
render_target_view_cb fn () voidptr render_target_view_cb fn () voidptr = unsafe { nil }
depth_stencil_view_cb fn () voidptr depth_stencil_view_cb fn () voidptr = unsafe { nil }
} }
pub type D3D11ContextDesc = C.sg_d3d11_context_desc pub type D3D11ContextDesc = C.sg_d3d11_context_desc

View File

@ -5,14 +5,14 @@ import sokol.memory
[typedef] [typedef]
pub struct C.sapp_allocator { pub struct C.sapp_allocator {
pub mut: pub mut:
alloc memory.FnAllocatorAlloc alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr user_data voidptr
} }
[typedef] [typedef]
pub struct C.sapp_logger { pub struct C.sapp_logger {
pub mut: pub mut:
log_cb memory.FnLogCb log_cb memory.FnLogCb = unsafe { nil }
user_data voidptr user_data voidptr
} }

View File

@ -37,18 +37,19 @@ pub type IconDesc = C.sapp_icon_desc
[typedef] [typedef]
pub struct C.sapp_desc { pub struct C.sapp_desc {
pub: pub:
init_cb fn () // these are the user-provided callbacks without user data // these are the user-provided callbacks without user data
frame_cb fn () init_cb fn () = unsafe { nil }
cleanup_cb fn () frame_cb fn () = unsafe { nil }
event_cb fn (&Event) //&sapp_event) cleanup_cb fn () = unsafe { nil }
fail_cb fn (&u8) event_cb fn (&Event) = unsafe { nil } // &sapp_event
fail_cb fn (&u8) = unsafe { nil }
user_data voidptr // these are the user-provided callbacks with user data user_data voidptr // these are the user-provided callbacks with user data
init_userdata_cb fn (voidptr) init_userdata_cb fn (voidptr) = unsafe { nil }
frame_userdata_cb fn (voidptr) frame_userdata_cb fn (voidptr) = unsafe { nil }
cleanup_userdata_cb fn (voidptr) cleanup_userdata_cb fn (voidptr) = unsafe { nil }
event_userdata_cb fn (&Event, voidptr) event_userdata_cb fn (&Event, voidptr) = unsafe { nil }
fail_userdata_cb fn (&char, voidptr) fail_userdata_cb fn (&char, voidptr) = unsafe { nil }
width int // the preferred width of the window / canvas width int // the preferred width of the window / canvas
height int // the preferred height of the window / canvas height int // the preferred height of the window / canvas

View File

@ -6,8 +6,8 @@ import sokol.memory
[typedef] [typedef]
pub struct C.sfons_allocator_t { pub struct C.sfons_allocator_t {
pub: pub:
alloc memory.FnAllocatorAlloc alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr user_data voidptr
} }

View File

@ -5,14 +5,14 @@ import sokol.memory
[typedef] [typedef]
pub struct C.sgl_allocator_t { pub struct C.sgl_allocator_t {
pub mut: pub mut:
alloc memory.FnAllocatorAlloc alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr user_data voidptr
} }
[typedef] [typedef]
pub struct C.sgl_logger_t { pub struct C.sgl_logger_t {
pub mut: pub mut:
log_cb memory.FnLogCb log_cb memory.FnLogCb = unsafe { nil }
user_data voidptr user_data voidptr
} }

View File

@ -24,9 +24,15 @@ mut:
pub type ThreadCB = fn (mut p PoolProcessor, idx int, task_id int) voidptr pub type ThreadCB = fn (mut p PoolProcessor, idx int, task_id int) voidptr
fn empty_cb(mut p PoolProcessor, idx int, task_id int) voidptr {
unsafe {
return nil
}
}
pub struct PoolProcessorConfig { pub struct PoolProcessorConfig {
maxjobs int maxjobs int
callback ThreadCB callback ThreadCB = empty_cb
} }
// new_pool_processor returns a new PoolProcessor instance. // new_pool_processor returns a new PoolProcessor instance.

View File

@ -15,7 +15,7 @@ pub interface Modifier {
pub type InspectorFn = fn (value &ast.Value, data voidptr) ! pub type InspectorFn = fn (value &ast.Value, data voidptr) !
struct Inspector { struct Inspector {
inspector_callback InspectorFn inspector_callback InspectorFn = unsafe { nil }
mut: mut:
data voidptr data voidptr
} }

View File

@ -10,8 +10,12 @@ mut:
pub type InspectorFn = fn (node &ast.Node, data voidptr) bool pub type InspectorFn = fn (node &ast.Node, data voidptr) bool
fn empty_callback(node &ast.Node, data voidptr) bool {
panic('empty ast.walker')
}
struct Inspector { struct Inspector {
inspector_callback InspectorFn inspector_callback InspectorFn = empty_callback
mut: mut:
data voidptr data voidptr
} }

View File

@ -70,6 +70,19 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
} }
} }
} }
// Do not allow uninitialized `fn` fields, or force `?fn`
// (allow them in `C.` structs)
if !c.is_builtin_mod && node.language == .v {
sym := c.table.sym(field.typ)
if sym.kind == .function {
if !field.typ.has_flag(.option) && !field.has_default_expr
&& field.attrs.filter(it.name == 'required').len == 0 {
error_msg := 'uninitialized `fn` struct fields are not allowed, since they can result in segfaults; use `?fn` or initialize the field with `=` (if you absolutely want to have unsafe function pointers, use `= unsafe { nil }`)'
c.note(error_msg, field.pos)
}
}
}
if field.has_default_expr { if field.has_default_expr {
c.expected_type = field.typ c.expected_type = field.typ
field.default_expr_typ = c.expr(mut field.default_expr) field.default_expr_typ = c.expr(mut field.default_expr)

View File

@ -1,5 +1,5 @@
struct St{ struct St {
attr fn() attr fn () = unsafe { nil }
} }
fn (s St) attr() {} fn (s St) attr() {}

View File

@ -1,3 +1,9 @@
vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.vv:2:2: notice: uninitialized `fn` struct fields are not allowed, since they can result in segfaults; use `?fn` or initialize the field with `=` (if you absolutely want to have unsafe function pointers, use `= unsafe { nil }`)
1 | struct Abc {
2 | f fn (voidptr)
| ~~~~~~~~~~~~~~
3 | }
4 |
vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.vv:7:3: error: cannot assign to field `f`: expected `fn (voidptr)`, not `fn (voidptr) ?` vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.vv:7:3: error: cannot assign to field `f`: expected `fn (voidptr)`, not `fn (voidptr) ?`
5 | fn main() { 5 | fn main() {
6 | a := Abc{ 6 | a := Abc{

View File

@ -1,3 +1,10 @@
vlib/v/checker/tests/generics_struct_init_err.vv:14:2: notice: uninitialized `fn` struct fields are not allowed, since they can result in segfaults; use `?fn` or initialize the field with `=` (if you absolutely want to have unsafe function pointers, use `= unsafe { nil }`)
12 |
13 | struct FnHolder2[T] {
14 | func fn (int) int
| ~~~~~~~~~~~~~~~~~
15 | }
16 |
vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: could not infer generic type `T` in generic struct `FnHolder2[T]` vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: could not infer generic type `T` in generic struct `FnHolder2[T]`
65 | ret = holder_call_22(neg, 5) 65 | ret = holder_call_22(neg, 5)
66 | assert ret == -5 66 | assert ret == -5

View File

@ -9,7 +9,7 @@ struct Alarm {
struct Clock { struct Clock {
mut: mut:
arr []Alarm arr []Alarm
alarm_fkt Fkt alarm_fkt Fkt = unsafe { nil }
} }
fn fkt(mut a Alarm) { fn fkt(mut a Alarm) {

View File

@ -13,7 +13,7 @@ const (
) )
struct Data { struct Data {
f fn (int) f fn (int) = unsafe { nil }
mut: mut:
value int = bar(0) value int = bar(0)
opt ?int = bar(0) opt ?int = bar(0)

View File

@ -1,5 +1,5 @@
struct App { struct App {
cb fn(x int) // the function signature doesn't make a difference cb fn(x int) = unsafe { nil } // the function signature doesn't make a difference
} }
fn main() { fn main() {

View File

@ -2,8 +2,8 @@ struct Data {
mut: mut:
n int n int
b bool b bool
f1 fn (voidptr) f1 fn (voidptr) [required]
f2 fn (...voidptr) f2 fn (...voidptr) [required]
data &Data data &Data
} }

View File

@ -1,7 +1,7 @@
vlib/v/checker/tests/unknown_type_in_anon_fn.vv:5:10: error: unknown type `Another` vlib/v/checker/tests/unknown_type_in_anon_fn.vv:5:10: error: unknown type `Another`
3 | struct Struc{ 3 | struct Struc{
4 | mut: 4 | mut:
5 | f fn (s Another, i int)? 5 | f fn (s Another, i int)? [required]
| ~~~~~~~ | ~~~~~~~
6 | } 6 | }
7 | 7 |

View File

@ -2,7 +2,7 @@ module main
struct Struc{ struct Struc{
mut: mut:
f fn (s Another, i int)? f fn (s Another, i int)? [required]
} }
fn main() {} fn main() {}

View File

@ -1,9 +1,9 @@
module main module main
struct Ok { struct Ok {
alibaba fn (Ok, ) alibaba fn (Ok, ) = unsafe { nil }
} }
struct OkInt { struct OkInt {
a fn (int, ) a fn (int, ) = unsafe { nil }
} }

View File

@ -446,7 +446,7 @@ type ControllerHandler = fn (ctx Context, mut url urllib.URL, host string, tid i
pub struct ControllerPath { pub struct ControllerPath {
pub: pub:
path string path string
handler ControllerHandler handler ControllerHandler = unsafe { nil }
pub mut: pub mut:
host string host string
} }
@ -1111,7 +1111,7 @@ fn (mut w Worker[T]) process_incomming_requests() {
[params] [params]
pub struct PoolParams[T] { pub struct PoolParams[T] {
handler fn () T [required] handler fn () T [required] = unsafe { nil }
nr_workers int = runtime.nr_jobs() nr_workers int = runtime.nr_jobs()
} }