From ee349691f99acdbf7d9fc2a624fe3b528ed87bdd Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 22 Jul 2020 18:28:53 +0100 Subject: [PATCH] v/checker: Warn about pointer indexing outside unsafe {} (#5918) --- vlib/builtin/builtin_nix.c.v | 2 +- vlib/builtin/sorted_map.v | 105 ++++++++++++++--------- vlib/builtin/string.v | 11 ++- vlib/builtin/utf8.v | 89 +++++++------------ vlib/encoding/base64/base64.v | 36 ++++---- vlib/encoding/utf8/utf8.v | 2 +- vlib/net/websocket/handshake.v | 8 +- vlib/net/websocket/utils.v | 22 ++--- vlib/net/websocket/ws.v | 73 ++++++++-------- vlib/os/environment.v | 4 +- vlib/os/os.v | 11 +-- vlib/os/os_nix.c.v | 2 +- vlib/os/os_windows.c.v | 2 +- vlib/rand/rand.v | 4 +- vlib/regex/regex.v | 47 ++++++---- vlib/v/checker/checker.v | 14 +++ vlib/v/checker/tests/unsafe_required.out | 24 ++++-- vlib/v/checker/tests/unsafe_required.vv | 12 +++ vlib/v/util/util.v | 12 +-- 19 files changed, 277 insertions(+), 203 deletions(-) diff --git a/vlib/builtin/builtin_nix.c.v b/vlib/builtin/builtin_nix.c.v index 9335976b3b..25faa04a83 100644 --- a/vlib/builtin/builtin_nix.c.v +++ b/vlib/builtin/builtin_nix.c.v @@ -86,7 +86,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { //////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames) csymbols := C.backtrace_symbols(&buffer[skipframes], nr_actual_frames) for i in 0 .. nr_actual_frames { - sframes << tos2( byteptr(csymbols[i]) ) + sframes << unsafe {tos2( byteptr(csymbols[i]) )} } for sframe in sframes { executable := sframe.all_before('(') diff --git a/vlib/builtin/sorted_map.v b/vlib/builtin/sorted_map.v index 3a99fe5f11..3850bb65c9 100644 --- a/vlib/builtin/sorted_map.v +++ b/vlib/builtin/sorted_map.v @@ -84,10 +84,10 @@ fn (mut m SortedMap) set(key string, value voidptr) { } return } - node = if key < parent.keys[child_index] { - &mapnode(parent.children[child_index]) + if key < parent.keys[child_index] { + node = unsafe {&mapnode(parent.children[child_index])} } else { - &mapnode(parent.children[child_index + 1]) + node = unsafe {&mapnode(parent.children[child_index + 1])} } } mut i := 0 @@ -116,7 +116,7 @@ fn (mut m SortedMap) set(key string, value voidptr) { } parent = node child_index = i - node = &mapnode(node.children[child_index]) + node = unsafe {&mapnode(node.children[child_index])} } } @@ -131,22 +131,30 @@ fn (mut n mapnode) split_child(child_index int, mut y mapnode) { if !isnil(y.children) { z.children = &voidptr(malloc(int(children_bytes))) for jj := degree - 1; jj >= 0; jj-- { - z.children[jj] = y.children[jj + degree] + unsafe { + z.children[jj] = y.children[jj + degree] + } } } if isnil(n.children) { n.children = &voidptr(malloc(int(children_bytes))) } - n.children[n.len + 1] = n.children[n.len] + unsafe { + n.children[n.len + 1] = n.children[n.len] + } for j := n.len; j > child_index; j-- { n.keys[j] = n.keys[j - 1] n.values[j] = n.values[j - 1] - n.children[j] = n.children[j - 1] + unsafe { + n.children[j] = n.children[j - 1] + } } n.keys[child_index] = y.keys[mid_index] n.values[child_index] = y.values[mid_index] - n.children[child_index] = voidptr(y) - n.children[child_index + 1] = voidptr(z) + unsafe { + n.children[child_index] = voidptr(y) + n.children[child_index + 1] = voidptr(z) + } n.len++ } @@ -164,7 +172,7 @@ fn (m SortedMap) get(key string, out voidptr) bool { if isnil(node.children) { break } - node = &mapnode(node.children[i + 1]) + node = unsafe {&mapnode(node.children[i + 1])} } return false } @@ -183,7 +191,7 @@ fn (m SortedMap) exists(key string) bool { if isnil(node.children) { break } - node = &mapnode(node.children[i + 1]) + node = unsafe {&mapnode(node.children[i + 1])} } return false } @@ -210,15 +218,17 @@ fn (mut n mapnode) remove_key(k string) bool { return false } flag := if idx == n.len {true} else {false} - if (&mapnode(n.children[idx])).len < degree { + if unsafe {&mapnode(n.children[idx])}.len < degree { n.fill(idx) } + mut node := &mapnode(0) if flag && idx > n.len { - return (&mapnode(n.children[idx - 1])).remove_key(k) + node = unsafe {&mapnode(n.children[idx - 1])} } else { - return (&mapnode(n.children[idx])).remove_key(k) + node = unsafe {&mapnode(n.children[idx])} } + return node.remove_key(k) } } @@ -232,34 +242,37 @@ fn (mut n mapnode) remove_from_leaf(idx int) { fn (mut n mapnode) remove_from_non_leaf(idx int) { k := n.keys[idx] - if &mapnode(n.children[idx]).len >= degree { - mut current := &mapnode(n.children[idx]) + if unsafe {&mapnode(n.children[idx])}.len >= degree { + mut current := unsafe {&mapnode(n.children[idx])} for !isnil(current.children) { - current = &mapnode(current.children[current.len]) + current = unsafe {&mapnode(current.children[current.len])} } predecessor := current.keys[current.len - 1] n.keys[idx] = predecessor n.values[idx] = current.values[current.len - 1] - (&mapnode(n.children[idx])).remove_key(predecessor) - } else if &mapnode(n.children[idx + 1]).len >= degree { - mut current := &mapnode(n.children[idx + 1]) + node := unsafe {&mapnode(n.children[idx])} + node.remove_key(predecessor) + } else if unsafe {&mapnode(n.children[idx + 1])}.len >= degree { + mut current := unsafe {&mapnode(n.children[idx + 1])} for !isnil(current.children) { - current = &mapnode(current.children[0]) + current = unsafe {&mapnode(current.children[0])} } successor := current.keys[0] n.keys[idx] = successor n.values[idx] = current.values[0] - (&mapnode(n.children[idx + 1])).remove_key(successor) + node := unsafe {&mapnode(n.children[idx + 1])} + node.remove_key(successor) } else { n.merge(idx) - (&mapnode(n.children[idx])).remove_key(k) + node := unsafe {&mapnode(n.children[idx])} + node.remove_key(k) } } fn (mut n mapnode) fill(idx int) { - if idx != 0 && &mapnode(n.children[idx - 1]).len >= degree { + if idx != 0 && unsafe {&mapnode(n.children[idx - 1])}.len >= degree { n.borrow_from_prev(idx) - } else if idx != n.len && &mapnode(n.children[idx + 1]).len >= degree { + } else if idx != n.len && unsafe {&mapnode(n.children[idx + 1])}.len >= degree { n.borrow_from_next(idx) } else if idx != n.len { n.merge(idx) @@ -269,21 +282,25 @@ fn (mut n mapnode) fill(idx int) { } fn (mut n mapnode) borrow_from_prev(idx int) { - mut child := &mapnode(n.children[idx]) - mut sibling := &mapnode(n.children[idx - 1]) + mut child := unsafe {&mapnode(n.children[idx])} + mut sibling := unsafe {&mapnode(n.children[idx - 1])} for i := child.len - 1; i >= 0; i-- { child.keys[i + 1] = child.keys[i] child.values[i + 1] = child.values[i] } if !isnil(child.children) { for i := child.len; i >= 0; i-- { - child.children[i + 1] = child.children[i] + unsafe { + child.children[i + 1] = child.children[i] + } } } child.keys[0] = n.keys[idx - 1] child.values[0] = n.values[idx - 1] if !isnil(child.children) { - child.children[0] = sibling.children[sibling.len] + unsafe { + child.children[0] = sibling.children[sibling.len] + } } n.keys[idx - 1] = sibling.keys[sibling.len - 1] n.values[idx - 1] = sibling.values[sibling.len - 1] @@ -292,12 +309,14 @@ fn (mut n mapnode) borrow_from_prev(idx int) { } fn (mut n mapnode) borrow_from_next(idx int) { - mut child := &mapnode(n.children[idx]) - mut sibling := &mapnode(n.children[idx + 1]) + mut child := unsafe {&mapnode(n.children[idx])} + mut sibling := unsafe {&mapnode(n.children[idx + 1])} child.keys[child.len] = n.keys[idx] child.values[child.len] = n.values[idx] if !isnil(child.children) { - child.children[child.len + 1] = sibling.children[0] + unsafe { + child.children[child.len + 1] = sibling.children[0] + } } n.keys[idx] = sibling.keys[0] n.values[idx] = sibling.values[0] @@ -307,7 +326,9 @@ fn (mut n mapnode) borrow_from_next(idx int) { } if !isnil(sibling.children) { for i := 1; i <= sibling.len; i++ { - sibling.children[i - 1] = sibling.children[i] + unsafe { + sibling.children[i - 1] = sibling.children[i] + } } } child.len++ @@ -315,8 +336,8 @@ fn (mut n mapnode) borrow_from_next(idx int) { } fn (mut n mapnode) merge(idx int) { - mut child := &mapnode(n.children[idx]) - sibling := &mapnode(n.children[idx + 1]) + mut child := unsafe {&mapnode(n.children[idx])} + sibling := unsafe {&mapnode(n.children[idx + 1])} child.keys[mid_index] = n.keys[idx] child.values[mid_index] = n.values[idx] for i in 0..sibling.len { @@ -325,7 +346,9 @@ fn (mut n mapnode) merge(idx int) { } if !isnil(child.children) { for i := 0; i <= sibling.len; i++ { - child.children[i + degree] = sibling.children[i] + unsafe { + child.children[i + degree] = sibling.children[i] + } } } for i := idx + 1; i < n.len; i++ { @@ -333,7 +356,9 @@ fn (mut n mapnode) merge(idx int) { n.values[i - 1] = n.values[i] } for i := idx + 2; i <= n.len; i++ { - n.children[i - 1] = n.children[i] + unsafe { + n.children[i - 1] = n.children[i] + } } child.len += sibling.len + 1 n.len-- @@ -355,7 +380,7 @@ pub fn (mut m SortedMap) delete(key string) { if isnil(m.root.children) { return } else { - m.root = &mapnode(m.root.children[0]) + m.root = unsafe {&mapnode(m.root.children[0])} } // free(tmp) } @@ -369,13 +394,13 @@ fn (n &mapnode) subkeys(mut keys []string, at int) int { // Traverse children and insert // keys inbetween children for i in 0..n.len { - child := &mapnode(n.children[i]) + child := unsafe {&mapnode(n.children[i])} position += child.subkeys(mut keys, position) keys[position] = n.keys[i] position++ } // Insert the keys of the last child - child := &mapnode(n.children[n.len]) + child := unsafe {&mapnode(n.children[n.len])} position += child.subkeys(mut keys, position) } else { // If leaf, insert keys diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 2b5d987248..525885df58 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -147,6 +147,7 @@ pub fn (s string) cstr() byteptr { */ // cstring_to_vstring creates a copy of cstr and turns it into a v string +[unsafe_fn] pub fn cstring_to_vstring(cstr byteptr) string { return tos_clone(cstr) } @@ -1432,12 +1433,16 @@ pub fn (s string) filter(func fn(b byte) bool) string { for i in 0 .. s.len { mut b := s[i] if func(b) { - buf[new_len] = b + unsafe { + buf[new_len] = b + } new_len++ } } - buf[new_len] = 0 - return string(buf, new_len) + unsafe { + buf[new_len] = 0 + return string(buf, new_len) + } } // Allows multi-line strings to be formatted in a way that removes white-space diff --git a/vlib/builtin/utf8.v b/vlib/builtin/utf8.v index d63aab9370..fefcd4d5e8 100644 --- a/vlib/builtin/utf8.v +++ b/vlib/builtin/utf8.v @@ -10,76 +10,45 @@ pub fn utf8_char_len(b byte) int { // Convert utf32 to utf8 // utf32 == Codepoint pub fn utf32_to_str(code u32) string { - icode := int(code) // Prevents doing casts everywhere mut buffer := malloc(5) - if icode <= 127/* 0x7F */ { - buffer[0] = byte(icode) - return tos(buffer, 1) - } - if icode <= 2047/* 0x7FF */ { - buffer[0] = 192/*0xC0*/ | byte(icode>>6)/* 110xxxxx */ - - buffer[1] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ - - return tos(buffer, 2) - } - if icode <= 65535/* 0xFFFF */ { - buffer[0] = 224/*0xE0*/ | byte(icode>>12)/* 1110xxxx */ - - buffer[1] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ - - buffer[2] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ - - return tos(buffer, 3) - } - if icode <= 1114111/* 0x10FFFF */ { - buffer[0] = 240/*0xF0*/ | byte(icode>>18)/* 11110xxx */ - - buffer[1] = 128/*0x80*/ | (byte(icode>>12) & 63/*0x3F*/)/* 10xxxxxx */ - - buffer[2] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ - - buffer[3] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ - - return tos(buffer, 4) - } - return '' + return utf32_to_str_no_malloc(code, buffer) } -// TODO copypasta pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string { icode := int(code) // Prevents doing casts everywhere - mut buffer := byteptr(buf) - if icode <= 127/* 0x7F */ { - buffer[0] = byte(icode) - return tos(buffer, 1) - } - if icode <= 2047/* 0x7FF */ { - buffer[0] = 192/*0xC0*/ | byte(icode>>6)/* 110xxxxx */ + unsafe { + mut buffer := byteptr(buf) + if icode <= 127/* 0x7F */ { + buffer[0] = byte(icode) + return tos(buffer, 1) + } + if icode <= 2047/* 0x7FF */ { + buffer[0] = 192/*0xC0*/ | byte(icode>>6)/* 110xxxxx */ - buffer[1] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ + buffer[1] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ - return tos(buffer, 2) - } - if icode <= 65535/* 0xFFFF */ { - buffer[0] = 224/*0xE0*/ | byte(icode>>12)/* 1110xxxx */ + return tos(buffer, 2) + } + if icode <= 65535/* 0xFFFF */ { + buffer[0] = 224/*0xE0*/ | byte(icode>>12)/* 1110xxxx */ - buffer[1] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ + buffer[1] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ - buffer[2] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ + buffer[2] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ - return tos(buffer, 3) - } - if icode <= 1114111/* 0x10FFFF */ { - buffer[0] = 240/*0xF0*/ | byte(icode>>18)/* 11110xxx */ + return tos(buffer, 3) + } + if icode <= 1114111/* 0x10FFFF */ { + buffer[0] = 240/*0xF0*/ | byte(icode>>18)/* 11110xxx */ - buffer[1] = 128/*0x80*/ | (byte(icode>>12) & 63/*0x3F*/)/* 10xxxxxx */ + buffer[1] = 128/*0x80*/ | (byte(icode>>12) & 63/*0x3F*/)/* 10xxxxxx */ - buffer[2] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ + buffer[2] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */ - buffer[3] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ + buffer[3] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */ - return tos(buffer, 4) + return tos(buffer, 4) + } } return '' } @@ -183,7 +152,7 @@ fn utf8_str_len(s string) int { mut l := 0 for i := 0; i < s.len; i++ { l++ - c := s.str[i] + c := unsafe {s.str[i]} if (c & (1 << 7)) != 0 { for t := byte(1 << 6); (c & t) != 0; t >>= 1 { i++ @@ -199,7 +168,7 @@ fn utf8_str_visible_length(s string) int { mut ul := 1 for i := 0; i < s.len; i+=ul { ul = 1 - c := s.str[i] + c := unsafe {s.str[i]} if (c & (1 << 7)) != 0 { for t := byte(1 << 6); (c & t) != 0; t >>= 1 { ul++ @@ -211,12 +180,12 @@ fn utf8_str_visible_length(s string) int { l++ // recognize combining characters if c == 0xcc || c == 0xcd { - r := (u16(c) << 8) | s.str[i+1] + r := (u16(c) << 8) | unsafe {s.str[i+1]} if r >= 0xcc80 && r < 0xcdb0 { // diacritical marks l-- } } else if c == 0xe1 || c == 0xe2 || c == 0xef { - r := (u32(c) << 16) | (u32(s.str[i+1]) << 8) | s.str[i+2] + r := (u32(c) << 16) | unsafe {(u32(s.str[i+1]) << 8) | s.str[i+2]} if (r >= 0xe1aab0 && r < 0xe1ac80) // diacritical marks extended || (r >= 0xe1b780 && r < 0xe1b880) // diacritical marks supplement || (r >= 0xe28390 && r < 0xe28480) // diacritical marks for symbols diff --git a/vlib/encoding/base64/base64.v b/vlib/encoding/base64/base64.v index c3481cecad..cdb7b33090 100644 --- a/vlib/encoding/base64/base64.v +++ b/vlib/encoding/base64/base64.v @@ -84,26 +84,28 @@ pub fn decode_in_buffer(data &string, buffer byteptr) int { mut char_c := 0 mut char_d := 0 if i < input_length { - char_a = index[d[i]] + char_a = index[unsafe {d[i]}] i++ } if i < input_length { - char_b = index[d[i]] + char_b = index[unsafe {d[i]}] i++ } if i < input_length { - char_c = index[d[i]] + char_c = index[unsafe {d[i]}] i++ } if i < input_length { - char_d = index[d[i]] + char_d = index[unsafe {d[i]}] i++ } decoded_bytes := (char_a << 18) | (char_b << 12) | (char_c << 6) | (char_d << 0) - b[j] = byte(decoded_bytes >> 16) - b[j+1] = byte((decoded_bytes >> 8) & 0xff) - b[j+2] = byte((decoded_bytes >> 0) & 0xff) + unsafe { + b[j] = byte(decoded_bytes >> 16) + b[j+1] = byte((decoded_bytes >> 8) & 0xff) + b[j+2] = byte((decoded_bytes >> 0) & 0xff) + } j += 3 } return output_length @@ -139,30 +141,34 @@ pub fn encode_in_buffer(data &string, buffer byteptr) int { mut octet_c := 0 if i < input_length { - octet_a = int(d[i]) + octet_a = int(unsafe {d[i]}) i++ } if i < input_length { - octet_b = int(d[i]) + octet_b = int(unsafe {d[i]}) i++ } if i < input_length { - octet_c = int(d[i]) + octet_c = int(unsafe {d[i]}) i++ } triple := ((octet_a << 0x10) + (octet_b << 0x08) + octet_c) - b[j] = etable[ (triple >> 3 * 6) & 63 ] // 63 is 0x3F - b[j+1] = etable[ (triple >> 2 * 6) & 63 ] - b[j+2] = etable[ (triple >> 1 * 6) & 63 ] - b[j+3] = etable[ (triple >> 0 * 6) & 63 ] + unsafe { + b[j] = etable[ (triple >> 3 * 6) & 63 ] // 63 is 0x3F + b[j+1] = etable[ (triple >> 2 * 6) & 63 ] + b[j+2] = etable[ (triple >> 1 * 6) & 63 ] + b[j+3] = etable[ (triple >> 0 * 6) & 63 ] + } j += 4 } padding_length := ending_table[input_length % 3] for i = 0; i < padding_length; i++ { - b[output_length - 1 - i] = `=` + unsafe { + b[output_length - 1 - i] = `=` + } } return output_length } diff --git a/vlib/encoding/utf8/utf8.v b/vlib/encoding/utf8/utf8.v index 0311a1f6cd..2a0c8d9fc4 100644 --- a/vlib/encoding/utf8/utf8.v +++ b/vlib/encoding/utf8/utf8.v @@ -14,7 +14,7 @@ pub fn validate_str(str string) bool { pub fn validate(data byteptr, len int) bool { mut state := Utf8State{} for i := 0; i < len; i++ { - s := data[i] + s := unsafe {data[i]} if s == 0 { break } diff --git a/vlib/net/websocket/handshake.v b/vlib/net/websocket/handshake.v index 587cfcb71b..e8510a1bc4 100644 --- a/vlib/net/websocket/handshake.v +++ b/vlib/net/websocket/handshake.v @@ -14,14 +14,16 @@ fn (mut ws Client) read_handshake(seckey string) { if res == 0 || res == -1 { ws.log.fatal('read_handshake: Failed to read handshake.') } - if buffer[bytes_read] == `\n` && + if unsafe {buffer[bytes_read] == `\n` && buffer[bytes_read - 1] == `\r` && buffer[bytes_read - 2] == `\n` && - buffer[bytes_read - 3] == `\r` { + buffer[bytes_read - 3] == `\r`} { break } bytes_read += buffer_size } - buffer[max_buffer - 1] = `\0` + unsafe { + buffer[max_buffer - 1] = `\0` + } ws.handshake_handler(string(byteptr(buffer)), seckey) } diff --git a/vlib/net/websocket/utils.v b/vlib/net/websocket/utils.v index d2c1ffe5a4..7610cc15eb 100644 --- a/vlib/net/websocket/utils.v +++ b/vlib/net/websocket/utils.v @@ -5,16 +5,18 @@ import crypto.sha1 import encoding.base64 fn htonl64(payload_len u64) byteptr { - mut ret := malloc(8) - ret[0] = byte(((payload_len & (u64(0xff) << 56)) >> 56) & 0xff) - ret[1] = byte(((payload_len & (u64(0xff) << 48)) >> 48) & 0xff) - ret[2] = byte(((payload_len & (u64(0xff) << 40)) >> 40) & 0xff) - ret[3] = byte(((payload_len & (u64(0xff) << 32)) >> 32) & 0xff) - ret[4] = byte(((payload_len & (u64(0xff) << 24)) >> 24) & 0xff) - ret[5] = byte(((payload_len & (u64(0xff) << 16)) >> 16) & 0xff) - ret[6] = byte(((payload_len & (u64(0xff) << 8)) >> 8) & 0xff) - ret[7] = byte(((payload_len & (u64(0xff) << 0)) >> 0) & 0xff) - return ret + unsafe { + mut ret := malloc(8) + ret[0] = byte(((payload_len & (u64(0xff) << 56)) >> 56) & 0xff) + ret[1] = byte(((payload_len & (u64(0xff) << 48)) >> 48) & 0xff) + ret[2] = byte(((payload_len & (u64(0xff) << 40)) >> 40) & 0xff) + ret[3] = byte(((payload_len & (u64(0xff) << 32)) >> 32) & 0xff) + ret[4] = byte(((payload_len & (u64(0xff) << 24)) >> 24) & 0xff) + ret[5] = byte(((payload_len & (u64(0xff) << 16)) >> 16) & 0xff) + ret[6] = byte(((payload_len & (u64(0xff) << 8)) >> 8) & 0xff) + ret[7] = byte(((payload_len & (u64(0xff) << 0)) >> 0) & 0xff) + return ret + } } fn create_masking_key() []byte { diff --git a/vlib/net/websocket/ws.v b/vlib/net/websocket/ws.v index 738456175d..ec7ffb1f43 100644 --- a/vlib/net/websocket/ws.v +++ b/vlib/net/websocket/ws.v @@ -355,19 +355,20 @@ pub fn (mut ws Client) read() int { } } if bytes_read == u64(header_len_offset) { - frame.fin = (data[0] & 0x80) == 0x80 - frame.rsv1 = (data[0] & 0x40) == 0x40 - frame.rsv2 = (data[0] & 0x20) == 0x20 - frame.rsv3 = (data[0] & 0x10) == 0x10 - frame.opcode = OPCode(int(data[0] & 0x7F)) - frame.mask = (data[1] & 0x80) == 0x80 - frame.payload_len = u64(data[1] & 0x7F) + data0 := unsafe {data[0]} + frame.fin = (data0 & 0x80) == 0x80 + frame.rsv1 = (data0 & 0x40) == 0x40 + frame.rsv2 = (data0 & 0x20) == 0x20 + frame.rsv3 = (data0 & 0x10) == 0x10 + frame.opcode = OPCode(int(data0 & 0x7F)) + frame.mask = (unsafe {data[1]} & 0x80) == 0x80 + frame.payload_len = u64(unsafe {data[1]} & 0x7F) // masking key if frame.mask { - frame.masking_key[0] = data[2] - frame.masking_key[1] = data[3] - frame.masking_key[2] = data[4] - frame.masking_key[3] = data[5] + frame.masking_key[0] = unsafe {data[2]} + frame.masking_key[1] = unsafe {data[3]} + frame.masking_key[2] = unsafe {data[4]} + frame.masking_key[3] = unsafe {data[5]} } payload_len = frame.payload_len frame_size = u64(header_len) + payload_len @@ -375,14 +376,14 @@ pub fn (mut ws Client) read() int { if frame.payload_len == u64(126) && bytes_read == u64(extended_payload16_end_byte) { header_len += 2 mut extended_payload_len := 0 - extended_payload_len |= data[2] << 8 - extended_payload_len |= data[3] << 0 + extended_payload_len |= unsafe {data[2]} << 8 + extended_payload_len |= unsafe {data[3]} << 0 // masking key if frame.mask { - frame.masking_key[0] = data[4] - frame.masking_key[1] = data[5] - frame.masking_key[2] = data[6] - frame.masking_key[3] = data[7] + frame.masking_key[0] = unsafe {data[4]} + frame.masking_key[1] = unsafe {data[5]} + frame.masking_key[2] = unsafe {data[6]} + frame.masking_key[3] = unsafe {data[7]} } payload_len = u64(extended_payload_len) frame_size = u64(header_len) + payload_len @@ -393,20 +394,20 @@ pub fn (mut ws Client) read() int { } else if frame.payload_len == u64(127) && bytes_read == u64(extended_payload64_end_byte) { header_len += 8 // TODO Not sure... mut extended_payload_len := u64(0) - extended_payload_len |= u64(data[2]) << 56 - extended_payload_len |= u64(data[3]) << 48 - extended_payload_len |= u64(data[4]) << 40 - extended_payload_len |= u64(data[5]) << 32 - extended_payload_len |= u64(data[6]) << 24 - extended_payload_len |= u64(data[7]) << 16 - extended_payload_len |= u64(data[8]) << 8 - extended_payload_len |= u64(data[9]) << 0 + extended_payload_len |= u64(unsafe {data[2]}) << 56 + extended_payload_len |= u64(unsafe {data[3]}) << 48 + extended_payload_len |= u64(unsafe {data[4]}) << 40 + extended_payload_len |= u64(unsafe {data[5]}) << 32 + extended_payload_len |= u64(unsafe {data[6]}) << 24 + extended_payload_len |= u64(unsafe {data[7]}) << 16 + extended_payload_len |= u64(unsafe {data[8]}) << 8 + extended_payload_len |= u64(unsafe {data[9]}) << 0 // masking key if frame.mask { - frame.masking_key[0] = data[10] - frame.masking_key[1] = data[11] - frame.masking_key[2] = data[12] - frame.masking_key[3] = data[13] + frame.masking_key[0] = unsafe {data[10]} + frame.masking_key[1] = unsafe {data[11]} + frame.masking_key[2] = unsafe {data[12]} + frame.masking_key[3] = unsafe {data[13]} } payload_len = extended_payload_len frame_size = u64(header_len) + payload_len @@ -419,7 +420,9 @@ pub fn (mut ws Client) read() int { // unmask the payload if frame.mask { for i in 0 .. payload_len { - data[header_len + i] ^= frame.masking_key[i % 4] & 0xff + unsafe { + data[header_len + i] ^= frame.masking_key[i % 4] & 0xff + } } } if ws.fragments.len > 0 && frame.opcode in [.text_frame, .binary_frame] { @@ -474,11 +477,13 @@ pub fn (mut ws Client) read() int { } ws.fragments = [] } - payload[payload_len] = `\0` + unsafe { + payload[payload_len] = `\0` + } if frame.opcode == .text_frame && payload_len > 0 { if !utf8.validate(payload, int(payload_len)) { ws.log.error('malformed utf8 payload') - ws.send_error_event('Recieved malformed utf8.') + ws.send_error_event('Received malformed utf8.') ws.close(1007, 'malformed utf8 payload') goto free_data return -1 @@ -556,10 +561,10 @@ pub fn (mut ws Client) read() int { mut code := 0 mut reason := '' if payload_len > 2 { - code = (int(data[header_len]) << 8) + int(data[header_len + 1]) + code = (int(unsafe {data[header_len]}) << 8) + int(unsafe {data[header_len + 1]}) header_len += 2 payload_len -= 2 - reason = string(&data[header_len]) + reason = unsafe {string(&data[header_len])} ws.log.info('Closing with reason: $reason & code: $code') if reason.len > 1 && !utf8.validate(reason.str, reason.len) { ws.log.error('malformed utf8 payload') diff --git a/vlib/os/environment.v b/vlib/os/environment.v index f2ec075921..174c8e1fbc 100644 --- a/vlib/os/environment.v +++ b/vlib/os/environment.v @@ -76,8 +76,8 @@ pub fn environ() map[string]string { C.FreeEnvironmentStringsW(estrings) } $else { e := &charptr(C.environ) - for i := 0; !isnil(e[i]); i++ { - eline := cstring_to_vstring(byteptr(e[i])) + for i := 0; !isnil(unsafe {e[i]}); i++ { + eline := unsafe {cstring_to_vstring(byteptr(e[i]))} eq_index := eline.index_byte(`=`) if eq_index > 0 { res[eline[0..eq_index]] = eline[eq_index + 1..] diff --git a/vlib/os/os.v b/vlib/os/os.v index d9f0e442e6..4f53a0288d 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -120,11 +120,12 @@ pub fn read_file(path string) ?string { fsize := C.ftell(fp) // C.fseek(fp, 0, SEEK_SET) // same as `C.rewind(fp)` below C.rewind(fp) - mut str := &byte(0) - unsafe { str = malloc(fsize + 1) } - C.fread(str, fsize, 1, fp) - str[fsize] = 0 - return string(str,fsize) + unsafe { + mut str := malloc(fsize + 1) + C.fread(str, fsize, 1, fp) + str[fsize] = 0 + return string(str,fsize) + } } /***************************** Utility ops ************************/ diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index 9e7293786b..4aa7bf114d 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -52,7 +52,7 @@ fn init_os_args(argc int, argv &&byte) []string { // mut args := []string{len:argc} for i in 0 .. argc { // args [i] = string(argv[i]) - args << string(argv[i]) + args << unsafe {string(argv[i])} } return args } diff --git a/vlib/os/os_windows.c.v b/vlib/os/os_windows.c.v index b3fc239b37..8db0752bcb 100644 --- a/vlib/os/os_windows.c.v +++ b/vlib/os/os_windows.c.v @@ -80,7 +80,7 @@ mut: fn init_os_args_wide(argc int, argv &byteptr) []string { mut args := []string{} for i in 0..argc { - args << string_from_wide(&u16(argv[i])) + args << string_from_wide(unsafe {&u16(argv[i])}) } return args } diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index afd2107a39..996ee21555 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -136,7 +136,9 @@ const ( pub fn string(len int) string { mut buf := malloc(len) for i in 0..len { - buf[i] = chars[intn(chars.len)] + unsafe { + buf[i] = chars[intn(chars.len)] + } } return string(buf, len) } diff --git a/vlib/regex/regex.v b/vlib/regex/regex.v index b4422386a5..4ec8fb12ce 100644 --- a/vlib/regex/regex.v +++ b/vlib/regex/regex.v @@ -90,18 +90,19 @@ fn utf8util_char_len(b byte) int { // get_char get a char from position i and return an u32 with the unicode code [inline] fn (re RE) get_char(in_txt string, i int) (u32,int) { + ini := unsafe {in_txt.str[i]} // ascii 8 bit if (re.flag & f_bin) !=0 || - in_txt.str[i] & 0x80 == 0 + ini & 0x80 == 0 { - return u32(in_txt.str[i]), 1 + return u32(ini), 1 } // unicode char - char_len := utf8util_char_len(in_txt.str[i]) + char_len := utf8util_char_len(ini) mut tmp := 0 mut ch := u32(0) for tmp < char_len { - ch = (ch << 8) | in_txt.str[i+tmp] + ch = (ch << 8) | unsafe {in_txt.str[i+tmp]} tmp++ } return ch,char_len @@ -112,16 +113,16 @@ fn (re RE) get_char(in_txt string, i int) (u32,int) { fn (re RE) get_charb(in_txt byteptr, i int) (u32,int) { // ascii 8 bit if (re.flag & f_bin) !=0 || - in_txt[i] & 0x80 == 0 + unsafe {in_txt[i]} & 0x80 == 0 { - return u32(in_txt[i]), 1 + return u32(unsafe {in_txt[i]}), 1 } // unicode char - char_len := utf8util_char_len(in_txt[i]) + char_len := utf8util_char_len(unsafe {in_txt[i]}) mut tmp := 0 mut ch := u32(0) for tmp < char_len { - ch = (ch << 8) | in_txt[i+tmp] + ch = (ch << 8) | unsafe {in_txt[i+tmp]} tmp++ } return ch,char_len @@ -488,15 +489,19 @@ fn (re RE) get_char_class(pc int) string { for cc_i >= 0 && cc_i < re.cc.len && re.cc[cc_i].cc_type != cc_end { if re.cc[cc_i].cc_type == cc_bsls { - buf_ptr[i++] = `\\` - buf_ptr[i++] = byte(re.cc[cc_i].ch0) + unsafe { + buf_ptr[i++] = `\\` + buf_ptr[i++] = byte(re.cc[cc_i].ch0) + } } else if re.cc[cc_i].ch0 == re.cc[cc_i].ch1 { tmp = 3 for tmp >= 0 { x := byte((re.cc[cc_i].ch0 >> (tmp*8)) & 0xFF) if x != 0 { - buf_ptr[i++] = x + unsafe { + buf_ptr[i++] = x + } } tmp-- } @@ -506,23 +511,31 @@ fn (re RE) get_char_class(pc int) string { for tmp >= 0 { x := byte((re.cc[cc_i].ch0 >> (tmp*8)) & 0xFF) if x != 0 { - buf_ptr[i++] = x + unsafe { + buf_ptr[i++] = x + } } tmp-- } - buf_ptr[i++] = `-` + unsafe { + buf_ptr[i++] = `-` + } tmp = 3 for tmp >= 0 { x := byte((re.cc[cc_i].ch1 >> (tmp*8)) & 0xFF) if x != 0 { - buf_ptr[i++] = x + unsafe { + buf_ptr[i++] = x + } } tmp-- } } cc_i++ } - buf_ptr[i] = byte(0) + unsafe { + buf_ptr[i] = byte(0) + } return tos_clone( buf_ptr ) } @@ -689,7 +702,9 @@ fn (re RE) parse_quantifier(in_txt string, in_i int) (int, int, int, bool) { mut ch := byte(0) for i < in_txt.len { - ch = in_txt.str[i] + unsafe { + ch = in_txt.str[i] + } //println("${ch:c} status: $status") diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 35c413abd5..72b91a9a2a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2993,6 +2993,20 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type { typ_sym.name.ends_with('ptr')) && !typ.has_flag(.variadic) { // byteptr, charptr etc c.error('type `$typ_sym.name` does not support indexing', node.pos) } + if !c.inside_unsafe && (typ.is_ptr() || typ.is_pointer()) { + mut is_ok := false + if node.left is ast.Ident { + ident := node.left as ast.Ident + scope := c.file.scope.innermost(ident.pos.pos) + if v := scope.find_var(ident.name) { + // `mut param []T` function parameter + is_ok = v.is_mut && v.is_arg && !typ.deref().is_ptr() + } + } + if !is_ok { + c.warn('pointer indexing is only allowed in `unsafe` blocks', node.pos) + } + } if node.index !is ast.RangeExpr { // [1] index_type := c.expr(node.index) c.check_index_type(typ_sym, index_type, node.pos) diff --git a/vlib/v/checker/tests/unsafe_required.out b/vlib/v/checker/tests/unsafe_required.out index 43dea90719..8429dadd90 100644 --- a/vlib/v/checker/tests/unsafe_required.out +++ b/vlib/v/checker/tests/unsafe_required.out @@ -1,34 +1,48 @@ -vlib/v/checker/tests/unsafe_required.v:4:6: error: pointer arithmetic is only allowed in `unsafe` blocks +vlib/v/checker/tests/unsafe_required.v:4:6: error: pointer arithmetic is only allowed in `unsafe` blocks 2 | v := 5 3 | mut p := &v 4 | p++ | ~~ 5 | p += 2 6 | _ := v -vlib/v/checker/tests/unsafe_required.v:5:7: error: pointer arithmetic is only allowed in `unsafe` blocks +vlib/v/checker/tests/unsafe_required.v:5:7: error: pointer arithmetic is only allowed in `unsafe` blocks 3 | mut p := &v 4 | p++ 5 | p += 2 | ~~ 6 | _ := v 7 | } -vlib/v/checker/tests/unsafe_required.v:11:14: error: pointer arithmetic is only allowed in `unsafe` blocks +vlib/v/checker/tests/unsafe_required.v:11:14: error: pointer arithmetic is only allowed in `unsafe` blocks 9 | fn test_ptr_infix() { 10 | v := 4 11 | mut q := &v - 1 | ^ 12 | q = q + 3 13 | _ := q -vlib/v/checker/tests/unsafe_required.v:12:9: error: pointer arithmetic is only allowed in `unsafe` blocks +vlib/v/checker/tests/unsafe_required.v:12:9: error: pointer arithmetic is only allowed in `unsafe` blocks 10 | v := 4 11 | mut q := &v - 1 12 | q = q + 3 | ^ 13 | _ := q 14 | _ := v -vlib/v/checker/tests/unsafe_required.v:24:7: error: method `S1.f` must be called from an `unsafe` block +vlib/v/checker/tests/unsafe_required.v:24:7: error: method `S1.f` must be called from an `unsafe` block 22 | fn test_funcs() { 23 | s := S1{} 24 | s.f() | ~~~ 25 | } + 26 | +vlib/v/checker/tests/unsafe_required.v:32:7: error: pointer indexing is only allowed in `unsafe` blocks + 30 | _ = b[0] + 31 | c := &b + 32 | _ = c[0] + | ~~~ + 33 | + 34 | v := 4 +vlib/v/checker/tests/unsafe_required.v:36:10: error: pointer indexing is only allowed in `unsafe` blocks + 34 | v := 4 + 35 | p := &v + 36 | _ = p[0] + | ~~~ + 37 | } diff --git a/vlib/v/checker/tests/unsafe_required.vv b/vlib/v/checker/tests/unsafe_required.vv index 917a2f0fec..686d9f5dd4 100644 --- a/vlib/v/checker/tests/unsafe_required.vv +++ b/vlib/v/checker/tests/unsafe_required.vv @@ -23,3 +23,15 @@ fn test_funcs() { s := S1{} s.f() } + +fn test_ptr_index(mut a []string) { + _ = a[0] + b := ['jo'] + _ = b[0] + c := &b + _ = c[0] + + v := 4 + p := &v + _ = p[0] +} diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index e7ead5268f..5482015d9d 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -212,11 +212,13 @@ pub fn read_file(file_path string) ?string { } // BOM check if raw_text.len >= 3 { - c_text := raw_text.str - if c_text[0] == 0xEF && c_text[1] == 0xBB && c_text[2] == 0xBF { - // skip three BOM bytes - offset_from_begin := 3 - raw_text = tos(c_text[offset_from_begin], vstrlen(c_text) - offset_from_begin) + unsafe { + c_text := raw_text.str + if c_text[0] == 0xEF && c_text[1] == 0xBB && c_text[2] == 0xBF { + // skip three BOM bytes + offset_from_begin := 3 + raw_text = tos(c_text[offset_from_begin], vstrlen(c_text) - offset_from_begin) + } } } return raw_text