From 3203a124b292dc561b2895cc6a9d0f535176959d Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Tue, 5 Jan 2021 15:02:04 +0000 Subject: [PATCH] checker: warn when casting between reference types outside of `unsafe` (#7892) --- vlib/live/common.v | 6 ++++-- vlib/math/unsafe.v | 8 ++++---- vlib/net/address.v | 2 +- vlib/net/tcp.v | 8 ++++---- vlib/net/udp.v | 2 +- vlib/regex/regex.v | 2 +- vlib/strconv/atof_test.v | 4 ++-- vlib/v/ast/ast.v | 2 +- vlib/v/checker/checker.v | 4 ++++ 9 files changed, 22 insertions(+), 16 deletions(-) diff --git a/vlib/live/common.v b/vlib/live/common.v index c661f5a79b..2e5c9f6c8b 100644 --- a/vlib/live/common.v +++ b/vlib/live/common.v @@ -60,7 +60,9 @@ pub fn info() &LiveReloadInfo { // started, and the structure LiveReloadInfo will not get updated. // All its fields will be 0, but still safe to access. mut x := &LiveReloadInfo{} - mut p := &u64(&C.g_live_info) - unsafe { *p = &u64(x) } + unsafe { + mut p := &u64(&C.g_live_info) + *p = &u64(x) + } return x } diff --git a/vlib/math/unsafe.v b/vlib/math/unsafe.v index 54a9f3b115..d3687ef9c4 100644 --- a/vlib/math/unsafe.v +++ b/vlib/math/unsafe.v @@ -6,7 +6,7 @@ module math // with the sign bit of f and the result in the same bit position. // f32_bits(f32_from_bits(x)) == x. pub fn f32_bits(f f32) u32 { - p := *(&u32(&f)) + p := *unsafe {&u32(&f)} return p } @@ -15,7 +15,7 @@ pub fn f32_bits(f f32) u32 { // and the result in the same bit position. // f32_from_bits(f32_bits(x)) == x. pub fn f32_from_bits(b u32) f32 { - p := *(&f32(&b)) + p := *unsafe {&f32(&b)} return p } @@ -23,7 +23,7 @@ pub fn f32_from_bits(b u32) f32 { // with the sign bit of f and the result in the same bit position, // and f64_bits(f64_from_bits(x)) == x. pub fn f64_bits(f f64) u64 { - p := *(&u64(&f)) + p := *unsafe {&u64(&f)} return p } @@ -32,7 +32,7 @@ pub fn f64_bits(f f64) u64 { // and the result in the same bit position. // f64_from_bits(f64_bits(x)) == x. pub fn f64_from_bits(b u64) f64 { - p := *(&f64(&b)) + p := *unsafe {&f64(&b)} return p } diff --git a/vlib/net/address.v b/vlib/net/address.v index 38eef6c92f..64d92b3b15 100644 --- a/vlib/net/address.v +++ b/vlib/net/address.v @@ -40,7 +40,7 @@ fn new_addr(addr C.sockaddr) ?Addr { } mut saddr := buf.bytestr() - hport := (&C.sockaddr_in(&addr)).sin_port + hport := unsafe {&C.sockaddr_in(&addr)}.sin_port port := C.ntohs(hport) $if windows { diff --git a/vlib/net/tcp.v b/vlib/net/tcp.v index 9745a9c318..86c378965c 100644 --- a/vlib/net/tcp.v +++ b/vlib/net/tcp.v @@ -160,7 +160,7 @@ pub fn (c TcpConn) peer_ip() ?string { buf := [44]byte{} peeraddr := C.sockaddr_in{} speeraddr := sizeof(peeraddr) - socket_error(C.getpeername(c.sock.handle, &C.sockaddr(&peeraddr), &speeraddr)) ? + socket_error(C.getpeername(c.sock.handle, unsafe {&C.sockaddr(&peeraddr)}, &speeraddr)) ? cstr := C.inet_ntop(C.AF_INET, &peeraddr.sin_addr, buf, sizeof(buf)) if cstr == 0 { return error('net.peer_ip: inet_ntop failed') @@ -190,7 +190,7 @@ pub fn listen_tcp(port int) ?TcpListener { addr.sin_addr.s_addr = C.htonl(C.INADDR_ANY) size := sizeof(C.sockaddr_in) // cast to the correct type - sockaddr := &C.sockaddr(&addr) + sockaddr := unsafe {&C.sockaddr(&addr)} socket_error(C.bind(s.handle, sockaddr, size)) ? socket_error(C.listen(s.handle, 128)) ? return TcpListener{ @@ -205,7 +205,7 @@ pub fn (l TcpListener) accept() ?TcpConn { unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_storage)) } size := sizeof(C.sockaddr_storage) // cast to correct type - sock_addr := &C.sockaddr(&addr) + sock_addr := unsafe {&C.sockaddr(&addr)} mut new_handle := C.accept(l.sock.handle, sock_addr, &size) if new_handle <= 0 { l.wait_for_accept() ? @@ -344,7 +344,7 @@ pub fn (s TcpSocket) address() ?Addr { mut addr := C.sockaddr_in{} size := sizeof(C.sockaddr_in) // cast to the correct type - sockaddr := &C.sockaddr(&addr) + sockaddr := unsafe {&C.sockaddr(&addr)} C.getsockname(s.handle, sockaddr, &size) return new_addr(sockaddr) } diff --git a/vlib/net/udp.v b/vlib/net/udp.v index e98741150f..e004ca913f 100644 --- a/vlib/net/udp.v +++ b/vlib/net/udp.v @@ -218,7 +218,7 @@ fn new_udp_socket(local_port int) ?UdpSocket { size := sizeof(C.sockaddr_in) // cast to the correct type - sockaddr := &C.sockaddr(&addr) + sockaddr := unsafe {&C.sockaddr(&addr)} socket_error(C.bind(s.handle, sockaddr, size))? diff --git a/vlib/regex/regex.v b/vlib/regex/regex.v index bd403dc660..c634dc9105 100644 --- a/vlib/regex/regex.v +++ b/vlib/regex/regex.v @@ -474,7 +474,7 @@ enum CharClass_parse_state { fn (re RE) get_char_class(pc int) string { buf := []byte{len:(re.cc.len)} - mut buf_ptr := &byte(&buf) + mut buf_ptr := unsafe {&byte(&buf)} mut cc_i := re.prog[pc].cc_index mut i := 0 diff --git a/vlib/strconv/atof_test.v b/vlib/strconv/atof_test.v index ea37d3d0ee..763903a942 100644 --- a/vlib/strconv/atof_test.v +++ b/vlib/strconv/atof_test.v @@ -62,8 +62,8 @@ fn test_atof() { // special cases mut f1 := f64(0.0) - mut ptr := &u64(&f1) - ptr = &u64(&f1) + mut ptr := unsafe {&u64(&f1)} + ptr = unsafe {&u64(&f1)} // double_plus_zero f1=0.0 diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index f4f4028273..cff6310ba6 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -948,7 +948,7 @@ pub: typ table.Type // `string` TODO rename to `type_to_cast_to` pos token.Position pub mut: - typname string + typname string // TypeSymbol.name expr_type table.Type // `byteptr` has_arg bool in_prexpr bool // is the parent node an ast.PrefixExpr diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b794047104..6b656fe71c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3421,6 +3421,10 @@ 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() { + 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) } if node.has_arg { c.expr(node.arg)