From 8fc33bc27d77f6a52b3d2b8fce4945b268fa47e4 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Tue, 5 Jan 2021 18:07:45 +0000 Subject: [PATCH] checker: warn when casting number or a voidptr to reference type outside unsafe (#7900) --- vlib/builtin/map.v | 22 +++++++++++----------- vlib/gg/gg.v | 12 ++++++------ vlib/live/common.v | 2 +- vlib/os/environment.c.v | 2 +- vlib/picoev/picoev.v | 2 +- vlib/sync/pool.v | 8 ++++---- vlib/v/checker/checker.v | 9 ++++++--- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index c01aa8b13f..d112cf45a1 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -230,44 +230,44 @@ pub mut: } fn map_hash_string(pkey voidptr) u64 { - key := *&string(pkey) + key := *unsafe { &string(pkey) } return hash.wyhash_c(key.str, u64(key.len), 0) } fn map_hash_int_1(pkey voidptr) u64 { - return hash.wyhash64_c(*&byte(pkey), 0) + return hash.wyhash64_c(*unsafe { &byte(pkey) }, 0) } fn map_hash_int_2(pkey voidptr) u64 { - return hash.wyhash64_c(*&u16(pkey), 0) + return hash.wyhash64_c(*unsafe { &u16(pkey) }, 0) } fn map_hash_int_4(pkey voidptr) u64 { - return hash.wyhash64_c(*&u32(pkey), 0) + return hash.wyhash64_c(*unsafe { &u32(pkey) }, 0) } fn map_hash_int_8(pkey voidptr) u64 { - return hash.wyhash64_c(*&u64(pkey), 0) + return hash.wyhash64_c(*unsafe { &u64(pkey) }, 0) } fn map_eq_string(a voidptr, b voidptr) bool { - return fast_string_eq(*&string(a), *&string(b)) + return fast_string_eq(*unsafe { &string(a) }, *unsafe { &string(b) }) } fn map_eq_int_1(a voidptr, b voidptr) bool { - return *&byte(a) == *&byte(b) + return unsafe { *&byte(a) == *&byte(b) } } fn map_eq_int_2(a voidptr, b voidptr) bool { - return *&u16(a) == *&u16(b) + return unsafe { *&u16(a) == *&u16(b) } } fn map_eq_int_4(a voidptr, b voidptr) bool { - return *&u32(a) == *&u32(b) + return unsafe { *&u32(a) == *&u32(b) } } fn map_eq_int_8(a voidptr, b voidptr) bool { - return *&u64(a) == *&u64(b) + return unsafe { *&u64(a) == *&u64(b) } } fn map_clone_string(dest voidptr, pkey voidptr) { @@ -302,7 +302,7 @@ fn map_clone_int_8(dest voidptr, pkey voidptr) { } fn map_free_string(pkey voidptr) { - (*&string(pkey)).free() + (*unsafe { &string(pkey) }).free() } fn map_free_nop(_ voidptr) { diff --git a/vlib/gg/gg.v b/vlib/gg/gg.v index 0c49a8ce78..563a199cb5 100644 --- a/vlib/gg/gg.v +++ b/vlib/gg/gg.v @@ -91,7 +91,7 @@ pub: } fn gg_init_sokol_window(user_data voidptr) { - mut g := &Context(user_data) + mut g := unsafe { &Context(user_data) } desc := sapp.create_desc() /* desc := C.sg_desc{ @@ -159,7 +159,7 @@ fn gg_init_sokol_window(user_data voidptr) { } fn gg_frame_fn(user_data voidptr) { - mut ctx := &Context(user_data) + mut ctx := unsafe { &Context(user_data) } if ctx.config.frame_fn == voidptr(0) { return } @@ -180,8 +180,8 @@ pub fn (mut ctx Context) refresh_ui() { } fn gg_event_fn(ce &C.sapp_event, user_data voidptr) { - e := &sapp.Event(ce) - mut g := &Context(user_data) + e := unsafe { &sapp.Event(ce) } + mut g := unsafe { &Context(user_data) } if g.config.event_fn != voidptr(0) { g.config.event_fn(e, g.config.user_data) } @@ -215,14 +215,14 @@ fn gg_event_fn(ce &C.sapp_event, user_data voidptr) { } fn gg_cleanup_fn(user_data voidptr) { - mut g := &Context(user_data) + mut g := unsafe { &Context(user_data) } if g.config.cleanup_fn != voidptr(0) { g.config.cleanup_fn(g.config.user_data) } } fn gg_fail_fn(msg charptr, user_data voidptr) { - mut g := &Context(user_data) + mut g := unsafe { &Context(user_data) } vmsg := tos3(msg) if g.config.fail_fn != voidptr(0) { g.config.fail_fn(vmsg, g.config.user_data) diff --git a/vlib/live/common.v b/vlib/live/common.v index 2e5c9f6c8b..ff242ef6e7 100644 --- a/vlib/live/common.v +++ b/vlib/live/common.v @@ -52,7 +52,7 @@ pub mut: // so that the user can set callbacks, read meta information, etc. pub fn info() &LiveReloadInfo { if C.g_live_info != 0 { - return &LiveReloadInfo(C.g_live_info) + return unsafe {&LiveReloadInfo(C.g_live_info)} } // When the current program is not compiled with -live, simply // return a new empty struct LiveReloadInfo in order to prevent diff --git a/vlib/os/environment.c.v b/vlib/os/environment.c.v index 31791dbee0..0fbf1e348b 100644 --- a/vlib/os/environment.c.v +++ b/vlib/os/environment.c.v @@ -81,7 +81,7 @@ pub fn environ() map[string]string { } C.FreeEnvironmentStringsW(estrings) } $else { - e := &charptr(C.environ) + e := unsafe { &charptr(C.environ) } for i := 0; !isnil(unsafe { e[i] }); i++ { eline := unsafe { cstring_to_vstring(byteptr(e[i])) } eq_index := eline.index_byte(`=`) diff --git a/vlib/picoev/picoev.v b/vlib/picoev/picoev.v index c71079d0be..d59dfe92bf 100644 --- a/vlib/picoev/picoev.v +++ b/vlib/picoev/picoev.v @@ -143,7 +143,7 @@ fn mysubstr(s byteptr, from int, len int) string { } fn rw_callback(loop &C.picoev_loop, fd int, events int, cb_arg voidptr) { - mut p := &Picoev(cb_arg) + mut p := unsafe {&Picoev(cb_arg)} if (events & C.PICOEV_TIMEOUT) != 0 { close_conn(loop, fd) p.idx[fd] = 0 diff --git a/vlib/sync/pool.v b/vlib/sync/pool.v index d5550c06a4..07c08ba2da 100644 --- a/vlib/sync/pool.v +++ b/vlib/sync/pool.v @@ -164,7 +164,7 @@ fn process_in_thread(mut pool PoolProcessor, task_id int) { pub fn (pool &PoolProcessor) get_string_item(idx int) string { // return *(&string(pool.items[idx])) // TODO: the below is a hack, remove it when v2 casting works again - return *(&string( pool.items[idx] )) + return *unsafe {&string( pool.items[idx] )} } // get_int_item - called by the worker callback. @@ -172,7 +172,7 @@ pub fn (pool &PoolProcessor) get_string_item(idx int) string { // TODO: remove the need for this when vfmt becomes smarter. pub fn (pool &PoolProcessor) get_int_item(idx int) int { item := pool.items[idx] - return *(&int(item)) + return *unsafe {&int(item)} } // TODO: uncomment, when generics work again @@ -241,14 +241,14 @@ pub fn (mut pool PoolProcessor) work_on_items_i(items []int) { pub fn (pool &PoolProcessor) get_results_s() []SResult { mut res := []SResult{} for i in 0 .. pool.results.len { - res << *(&SResult(pool.results[i])) + res << *unsafe {&SResult(pool.results[i])} } return res } pub fn (pool &PoolProcessor) get_results_i() []IResult { mut res := []IResult{} for i in 0 .. pool.results.len { - res << *(&IResult(pool.results[i])) + res << *unsafe {&IResult(pool.results[i])} } return res } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c131cc9123..02c76a2ff3 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3426,10 +3426,13 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) table.Type { // variadic case can happen when arrays are converted into variadic msg := if node.expr_type.has_flag(.optional) { 'an optional' } else { 'a variadic' } c.error('cannot type cast $msg', node.pos) - } else if !c.inside_unsafe && node.typ.is_ptr() && node.expr_type.is_ptr() { + } else if !c.inside_unsafe && node.typ.is_ptr() && + (node.expr_type.is_ptr() || node.expr_type == table.voidptr_type || + (node.expr_type.is_number() && node.expr !is ast.IntegerLiteral)) { + // ignore &Type(0) for now ft := c.table.type_to_str(node.expr_type) tt := c.table.type_to_str(node.typ) - c.warn('casting `$ft` to `$tt` is only allowed in `unsafe` code', node.pos) + c.warn('casting a `$ft` to `$tt` is only allowed in `unsafe` code', node.pos) } if node.has_arg { c.expr(node.arg) @@ -5183,7 +5186,7 @@ fn (mut c Checker) verify_all_vweb_routes() { if m.return_type == typ_vweb_result { is_ok, nroute_attributes, nargs := c.verify_vweb_params_for_method(m) if !is_ok { - f := &ast.FnDecl(m.source_fn) + f := unsafe { &ast.FnDecl(m.source_fn) } if isnil(f) { continue }