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:
parent
453137384e
commit
428fd7f57f
@ -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
|
||||||
|
@ -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 = [
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
struct St{
|
struct St {
|
||||||
attr fn()
|
attr fn () = unsafe { nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s St) attr() {}
|
fn (s St) attr() {}
|
||||||
|
@ -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{
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 |
|
||||||
|
@ -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() {}
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user