checker: warn when casting number or a voidptr to reference type outside unsafe (#7900)

pull/7902/head
Nick Treleaven 2021-01-05 18:07:45 +00:00 committed by GitHub
parent 3e04dfc79f
commit 8fc33bc27d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 30 additions and 27 deletions

View File

@ -230,44 +230,44 @@ pub mut:
} }
fn map_hash_string(pkey voidptr) u64 { fn map_hash_string(pkey voidptr) u64 {
key := *&string(pkey) key := *unsafe { &string(pkey) }
return hash.wyhash_c(key.str, u64(key.len), 0) return hash.wyhash_c(key.str, u64(key.len), 0)
} }
fn map_hash_int_1(pkey voidptr) u64 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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) { 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) { fn map_free_string(pkey voidptr) {
(*&string(pkey)).free() (*unsafe { &string(pkey) }).free()
} }
fn map_free_nop(_ voidptr) { fn map_free_nop(_ voidptr) {

View File

@ -91,7 +91,7 @@ pub:
} }
fn gg_init_sokol_window(user_data voidptr) { fn gg_init_sokol_window(user_data voidptr) {
mut g := &Context(user_data) mut g := unsafe { &Context(user_data) }
desc := sapp.create_desc() desc := sapp.create_desc()
/* /*
desc := C.sg_desc{ desc := C.sg_desc{
@ -159,7 +159,7 @@ fn gg_init_sokol_window(user_data voidptr) {
} }
fn gg_frame_fn(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) { if ctx.config.frame_fn == voidptr(0) {
return return
} }
@ -180,8 +180,8 @@ pub fn (mut ctx Context) refresh_ui() {
} }
fn gg_event_fn(ce &C.sapp_event, user_data voidptr) { fn gg_event_fn(ce &C.sapp_event, user_data voidptr) {
e := &sapp.Event(ce) e := unsafe { &sapp.Event(ce) }
mut g := &Context(user_data) mut g := unsafe { &Context(user_data) }
if g.config.event_fn != voidptr(0) { if g.config.event_fn != voidptr(0) {
g.config.event_fn(e, g.config.user_data) 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) { 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) { if g.config.cleanup_fn != voidptr(0) {
g.config.cleanup_fn(g.config.user_data) g.config.cleanup_fn(g.config.user_data)
} }
} }
fn gg_fail_fn(msg charptr, user_data voidptr) { fn gg_fail_fn(msg charptr, user_data voidptr) {
mut g := &Context(user_data) mut g := unsafe { &Context(user_data) }
vmsg := tos3(msg) vmsg := tos3(msg)
if g.config.fail_fn != voidptr(0) { if g.config.fail_fn != voidptr(0) {
g.config.fail_fn(vmsg, g.config.user_data) g.config.fail_fn(vmsg, g.config.user_data)

View File

@ -52,7 +52,7 @@ pub mut:
// so that the user can set callbacks, read meta information, etc. // so that the user can set callbacks, read meta information, etc.
pub fn info() &LiveReloadInfo { pub fn info() &LiveReloadInfo {
if C.g_live_info != 0 { 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 // When the current program is not compiled with -live, simply
// return a new empty struct LiveReloadInfo in order to prevent // return a new empty struct LiveReloadInfo in order to prevent

View File

@ -81,7 +81,7 @@ pub fn environ() map[string]string {
} }
C.FreeEnvironmentStringsW(estrings) C.FreeEnvironmentStringsW(estrings)
} $else { } $else {
e := &charptr(C.environ) e := unsafe { &charptr(C.environ) }
for i := 0; !isnil(unsafe { e[i] }); i++ { for i := 0; !isnil(unsafe { e[i] }); i++ {
eline := unsafe { cstring_to_vstring(byteptr(e[i])) } eline := unsafe { cstring_to_vstring(byteptr(e[i])) }
eq_index := eline.index_byte(`=`) eq_index := eline.index_byte(`=`)

View File

@ -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) { 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 { if (events & C.PICOEV_TIMEOUT) != 0 {
close_conn(loop, fd) close_conn(loop, fd)
p.idx[fd] = 0 p.idx[fd] = 0

View File

@ -164,7 +164,7 @@ fn process_in_thread(mut pool PoolProcessor, task_id int) {
pub fn (pool &PoolProcessor) get_string_item(idx int) string { pub fn (pool &PoolProcessor) get_string_item(idx int) string {
// return *(&string(pool.items[idx])) // return *(&string(pool.items[idx]))
// TODO: the below is a hack, remove it when v2 casting works again // 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. // 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. // TODO: remove the need for this when vfmt becomes smarter.
pub fn (pool &PoolProcessor) get_int_item(idx int) int { pub fn (pool &PoolProcessor) get_int_item(idx int) int {
item := pool.items[idx] item := pool.items[idx]
return *(&int(item)) return *unsafe {&int(item)}
} }
// TODO: uncomment, when generics work again // 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 { pub fn (pool &PoolProcessor) get_results_s() []SResult {
mut res := []SResult{} mut res := []SResult{}
for i in 0 .. pool.results.len { for i in 0 .. pool.results.len {
res << *(&SResult(pool.results[i])) res << *unsafe {&SResult(pool.results[i])}
} }
return res return res
} }
pub fn (pool &PoolProcessor) get_results_i() []IResult { pub fn (pool &PoolProcessor) get_results_i() []IResult {
mut res := []IResult{} mut res := []IResult{}
for i in 0 .. pool.results.len { for i in 0 .. pool.results.len {
res << *(&IResult(pool.results[i])) res << *unsafe {&IResult(pool.results[i])}
} }
return res return res
} }

View File

@ -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 // variadic case can happen when arrays are converted into variadic
msg := if node.expr_type.has_flag(.optional) { 'an optional' } else { 'a variadic' } msg := if node.expr_type.has_flag(.optional) { 'an optional' } else { 'a variadic' }
c.error('cannot type cast $msg', node.pos) 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) ft := c.table.type_to_str(node.expr_type)
tt := c.table.type_to_str(node.typ) 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 { if node.has_arg {
c.expr(node.arg) c.expr(node.arg)
@ -5183,7 +5186,7 @@ fn (mut c Checker) verify_all_vweb_routes() {
if m.return_type == typ_vweb_result { if m.return_type == typ_vweb_result {
is_ok, nroute_attributes, nargs := c.verify_vweb_params_for_method(m) is_ok, nroute_attributes, nargs := c.verify_vweb_params_for_method(m)
if !is_ok { if !is_ok {
f := &ast.FnDecl(m.source_fn) f := unsafe { &ast.FnDecl(m.source_fn) }
if isnil(f) { if isnil(f) {
continue continue
} }