From 0b49e4db1c575d2d135d3083746dc65f54ce5327 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 3 Jul 2020 17:10:10 +0100 Subject: [PATCH] v/checker.v: disallow pointer arithmetic for InfixExpr outside unsafe {} (#5640) --- vlib/builtin/array.v | 108 +++++++++++++++++++++-------- vlib/builtin/int.v | 32 ++++++--- vlib/builtin/map.v | 38 +++++++--- vlib/builtin/option.v | 6 +- vlib/builtin/sorted_map.v | 4 +- vlib/builtin/utf8.v | 8 ++- vlib/hash/wyhash/wyhash.v | 52 +++++++------- vlib/net/websocket/handshake.v | 5 +- vlib/net/websocket/ws.v | 24 +++++-- vlib/os/environment.v | 6 +- vlib/picoev/picoev.v | 23 ++++-- vlib/v/checker/checker.v | 4 ++ vlib/v/tests/ptr_arithmetic_test.v | 4 +- 13 files changed, 221 insertions(+), 93 deletions(-) diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index c3c0a69499..462e6dfc7a 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -29,7 +29,7 @@ fn __new_array(mylen int, cap int, elm_size int) array { fn __new_array_with_default(mylen int, cap int, elm_size int, val voidptr) array { cap_ := if cap < mylen { mylen } else { cap } - arr := array{ + mut arr := array{ element_size: elm_size data: vcalloc(cap_ * elm_size) len: mylen @@ -37,7 +37,9 @@ fn __new_array_with_default(mylen int, cap int, elm_size int, val voidptr) array } if val != 0 { for i in 0..arr.len { - C.memcpy(charptr(arr.data) + i*elm_size, val, elm_size) + unsafe { + arr.set_unsafe(i, val) + } } } return arr @@ -45,7 +47,7 @@ fn __new_array_with_default(mylen int, cap int, elm_size int, val voidptr) array fn __new_array_with_array_default(mylen int, cap int, elm_size int, val array) array { cap_ := if cap < mylen { mylen } else { cap } - arr := array{ + mut arr := array{ element_size: elm_size data: vcalloc(cap_ * elm_size) len: mylen @@ -53,7 +55,9 @@ fn __new_array_with_array_default(mylen int, cap int, elm_size int, val array) a } for i in 0..arr.len { val_clone := val.clone() - C.memcpy(charptr(arr.data) + i*elm_size, &val_clone, elm_size) + unsafe { + arr.set_unsafe(i, &val_clone) + } } return arr } @@ -123,9 +127,13 @@ pub fn (a array) repeat(count int) array { ary := array{} C.memcpy(&ary, a.data, sizeof(array)) ary_clone := ary.clone() - C.memcpy(byteptr(arr.data) + i * a.len * a.element_size, &ary_clone, a.len * a.element_size) + unsafe { + C.memcpy(arr.get_unsafe(i * a.len), &ary_clone, a.len * a.element_size) + } } else { - C.memcpy(byteptr(arr.data) + i * a.len * a.element_size, byteptr(a.data), a.len * a.element_size) + unsafe { + C.memcpy(arr.get_unsafe(i * a.len), byteptr(a.data), a.len * a.element_size) + } } } return arr @@ -144,9 +152,10 @@ pub fn (mut a array) insert(i int, val voidptr) { } } a.ensure_cap(a.len + 1) - size := a.element_size - C.memmove(byteptr(a.data) + (i + 1) * size, byteptr(a.data) + i * size, (a.len - i) * size) - C.memcpy(byteptr(a.data) + i * size, val, size) + unsafe { + C.memmove(a.get_unsafe(i + 1), a.get_unsafe(i), (a.len - i) * a.element_size) + a.set_unsafe(i, val) + } a.len++ } @@ -159,8 +168,11 @@ pub fn (mut a array) insert_many(i int, val voidptr, size int) { } a.ensure_cap(a.len + size) elem_size := a.element_size - C.memmove(byteptr(a.data) + (i + size) * elem_size, byteptr(a.data) + i * elem_size, (a.len - i) * elem_size) - C.memcpy(byteptr(a.data) + i * elem_size, val, size * elem_size) + unsafe { + iptr := a.get_unsafe(i) + C.memmove(a.get_unsafe(i + size), iptr, (a.len - i) * elem_size) + C.memcpy(iptr, val, size * elem_size) + } a.len += size } @@ -181,10 +193,11 @@ pub fn (mut a array) delete(i int) { panic('array.delete: index out of range (i == $i, a.len == $a.len)') } } - size := a.element_size // NB: if a is [12,34], a.len = 2, a.delete(0) // should move (2-0-1) elements = 1 element (the 34) forward - C.memmove(byteptr(a.data) + i * size, byteptr(a.data) + (i + 1) * size, (a.len - i - 1) * size) + unsafe { + C.memmove(a.get_unsafe(i), a.get_unsafe(i + 1), (a.len - i - 1) * a.element_size) + } a.len-- } @@ -201,6 +214,14 @@ pub fn (mut a array) trim(index int) { } } +// we manually inline this for single operations for performance without -prod +[inline] [unsafe_fn] +fn (a array) get_unsafe(i int) voidptr { + unsafe { + return byteptr(a.data) + i * a.element_size + } +} + // Private function. Used to implement array[] operator fn (a array) get(i int) voidptr { $if !no_bounds_checking? { @@ -208,7 +229,9 @@ fn (a array) get(i int) voidptr { panic('array.get: index out of range (i == $i, a.len == $a.len)') } } - return byteptr(a.data) + i * a.element_size + unsafe { + return byteptr(a.data) + i * a.element_size + } } // array.first returns the first element of the array @@ -228,7 +251,9 @@ pub fn (a array) last() voidptr { panic('array.last: array is empty') } } - return byteptr(a.data) + (a.len - 1) * a.element_size + unsafe { + return byteptr(a.data) + (a.len - 1) * a.element_size + } } // array.slice returns an array using the same buffer as original array @@ -248,10 +273,14 @@ fn (a array) slice(start, _end int) array { panic('array.slice: slice bounds out of range ($start < 0)') } } + mut data := byteptr(0) + unsafe { + data = byteptr(a.data) + start * a.element_size + } l := end - start res := array{ element_size: a.element_size - data: byteptr(a.data) + start * a.element_size + data: data len: l cap: l } @@ -276,7 +305,7 @@ pub fn (a &array) clone() array { if size == 0 { size++ } - arr := array{ + mut arr := array{ element_size: a.element_size data: vcalloc(size) len: a.len @@ -286,9 +315,9 @@ pub fn (a &array) clone() array { if a.element_size == sizeof(array) { for i in 0..a.len { ar := array{} - C.memcpy(&ar, byteptr(a.data) + i * a.element_size, sizeof(array)) + C.memcpy(&ar, a.get_unsafe(i), sizeof(array)) ar_clone := ar.clone() - C.memcpy(byteptr(arr.data) + i * a.element_size, &ar_clone, a.element_size) + arr.set_unsafe(i, &ar_clone) } } else { C.memcpy(byteptr(arr.data), a.data, a.cap * a.element_size) @@ -309,16 +338,28 @@ fn (a &array) slice_clone(start, _end int) array { panic('array.slice: slice bounds out of range ($start < 0)') } } + mut data := byteptr(0) + unsafe { + data = byteptr(a.data) + start * a.element_size + } l := end - start res := array{ element_size: a.element_size - data: byteptr(a.data) + start * a.element_size + data: data len: l cap: l } return res.clone() } +// we manually inline this for single operations for performance without -prod +[inline] [unsafe_fn] +fn (mut a array) set_unsafe(i int, val voidptr) { + unsafe { + C.memcpy(byteptr(a.data) + a.element_size * i, val, a.element_size) + } +} + // Private function. Used to implement assigment to the array element. fn (mut a array) set(i int, val voidptr) { $if !no_bounds_checking? { @@ -326,12 +367,16 @@ fn (mut a array) set(i int, val voidptr) { panic('array.set: index out of range (i == $i, a.len == $a.len)') } } - C.memcpy(byteptr(a.data) + a.element_size * i, val, a.element_size) + unsafe { + C.memcpy(byteptr(a.data) + a.element_size * i, val, a.element_size) + } } fn (mut a array) push(val voidptr) { a.ensure_cap(a.len + 1) - C.memcpy(byteptr(a.data) + a.element_size * a.len, val, a.element_size) + unsafe { + C.memcpy(byteptr(a.data) + a.element_size * a.len, val, a.element_size) + } a.len++ } @@ -342,11 +387,15 @@ pub fn (mut a3 array) push_many(val voidptr, size int) { // handle `arr << arr` copy := a3.clone() a3.ensure_cap(a3.len + size) - //C.memcpy(a.data, copy.data, copy.element_size * copy.len) - C.memcpy(byteptr(a3.data) + a3.element_size * a3.len, copy.data, a3.element_size * size) + unsafe { + //C.memcpy(a.data, copy.data, copy.element_size * copy.len) + C.memcpy(a3.get_unsafe(a3.len), copy.data, a3.element_size * size) + } } else { a3.ensure_cap(a3.len + size) - C.memcpy(byteptr(a3.data) + a3.element_size * a3.len, val, a3.element_size * size) + unsafe { + C.memcpy(a3.get_unsafe(a3.len), val, a3.element_size * size) + } } a3.len += size } @@ -357,15 +406,16 @@ pub fn (a array) reverse() array { if a.len < 2 { return a } - arr := array{ + mut arr := array{ element_size: a.element_size data: vcalloc(a.cap * a.element_size) len: a.len cap: a.cap } for i in 0..a.len { - //C.memcpy(arr.data + i * arr.element_size, &a[a.len - 1 - i], arr.element_size) - C.memcpy(byteptr(arr.data) + i * arr.element_size, byteptr(a.data) + (a.len - 1 - i) * arr.element_size, arr.element_size) + unsafe { + arr.set_unsafe(i, a.get_unsafe(a.len - 1 - i)) + } } return arr } @@ -591,7 +641,7 @@ pub fn compare_f32(a, b &f32) int { pub fn (a array) pointers() []voidptr { mut res := []voidptr{} for i in 0..a.len { - res << byteptr(a.data) + i * a.element_size + res << a.get_unsafe(i) } return res } diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 250dbb3c65..805569d6ce 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -93,7 +93,9 @@ pub fn (nn int) str_l(max int) string { buf[index] = `-` } - C.memmove(buf,buf+index, (max-index)+1 ) + unsafe { + C.memmove(buf,buf+index, (max-index)+1 ) + } return tos(buf, (max-index)) //return tos(buf + index, (max-index)) } @@ -139,7 +141,9 @@ pub fn (nn u32) str() string { index++ } - C.memmove(buf,buf+index, (max-index)+1 ) + unsafe { + C.memmove(buf,buf+index, (max-index)+1 ) + } return tos(buf, (max-index)) //return tos(buf + index, (max-index)) } @@ -186,7 +190,9 @@ pub fn (nn i64) str() string { buf[index] = `-` } - C.memmove(buf,buf+index, (max-index)+1 ) + unsafe { + C.memmove(buf,buf+index, (max-index)+1 ) + } return tos(buf, (max-index)) //return tos(buf + index, (max-index)) } @@ -216,7 +222,9 @@ pub fn (nn u64) str() string { index++ } - C.memmove(buf,buf+index, (max-index)+1 ) + unsafe { + C.memmove(buf,buf+index, (max-index)+1 ) + } return tos(buf, (max-index)) //return tos(buf + index, (max-index)) } @@ -260,7 +268,9 @@ pub fn (nn byte) hex() string { //buf[index] = `0` index++ - return tos(buf + index, (max - index)) + unsafe { + return tos(buf + index, (max - index)) + } } pub fn (nn i8) hex() string { @@ -287,7 +297,9 @@ pub fn (nn u16) hex() string { //buf[index] = `0` index++ - return tos(buf + index, (max - index)) + unsafe { + return tos(buf + index, (max - index)) + } } pub fn (nn i16) hex() string { @@ -314,7 +326,9 @@ pub fn (nn u32) hex() string { //buf[index] = `0` index++ - return tos(buf + index, (max - index)) + unsafe { + return tos(buf + index, (max - index)) + } } pub fn (nn int) hex() string { @@ -345,7 +359,9 @@ pub fn (nn u64) hex() string { //buf[index] = `0` index++ - C.memmove(buf,buf+index, (max-index)+1 ) + unsafe { + C.memmove(buf,buf+index, (max-index)+1 ) + } return tos(buf, (max-index)) //return tos(buf + index, (max-index)) } diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index e9d403f8c6..9884a667dc 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -127,7 +127,9 @@ fn (mut d DenseArray) push(key string, value voidptr) u32 { } push_index := d.len d.keys[push_index] = key - C.memcpy(d.values + push_index * u32(d.value_bytes), value, d.value_bytes) + unsafe { + C.memcpy(d.values + push_index * u32(d.value_bytes), value, d.value_bytes) + } d.len++ return push_index } @@ -138,7 +140,9 @@ fn (d DenseArray) get(i int) voidptr { panic('DenseArray.get: index out of range (i == $i, d.len == $d.len)') } } - return byteptr(d.keys) + i * int(sizeof(string)) + unsafe { + return byteptr(d.keys) + i * int(sizeof(string)) + } } // Move all zeros to the end of the array and resize array @@ -152,9 +156,11 @@ fn (mut d DenseArray) zeros_to_end() { d.keys[count] = d.keys[i] d.keys[i] = tmp_key // swap values (TODO: optimize) - C.memcpy(tmp_value, d.values + count * u32(d.value_bytes), d.value_bytes) - C.memcpy(d.values + count * u32(d.value_bytes), d.values + i * d.value_bytes, d.value_bytes) - C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes) + unsafe { + C.memcpy(tmp_value, d.values + count * u32(d.value_bytes), d.value_bytes) + C.memcpy(d.values + count * u32(d.value_bytes), d.values + i * d.value_bytes, d.value_bytes) + C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes) + } count++ } } @@ -206,7 +212,9 @@ fn new_map_1(value_bytes int) map { fn new_map_init(n, value_bytes int, keys &string, values voidptr) map { mut out := new_map_1(value_bytes) for i in 0 .. n { - out.set(keys[i], byteptr(values) + i * value_bytes) + unsafe { + out.set(keys[i], byteptr(values) + i * value_bytes) + } } return out } @@ -258,8 +266,10 @@ fn (mut m map) ensure_extra_metas(probe_count u32) { if (probe_count << 1) == m.extra_metas { m.extra_metas += extra_metas_inc mem_size := (m.cap + 2 + m.extra_metas) - m.metas = &u32(C.realloc(m.metas, sizeof(u32) * mem_size)) - C.memset(m.metas + mem_size - extra_metas_inc, 0, sizeof(u32) * extra_metas_inc) + unsafe { + m.metas = &u32(C.realloc(m.metas, sizeof(u32) * mem_size)) + C.memset(m.metas + mem_size - extra_metas_inc, 0, sizeof(u32) * extra_metas_inc) + } // Should almost never happen if probe_count == 252 { panic('Probe overflow') @@ -282,7 +292,9 @@ fn (mut m map) set(k string, value voidptr) { for meta == m.metas[index] { kv_index := m.metas[index + 1] if fast_string_eq(key, m.key_values.keys[kv_index]) { - C.memcpy(m.key_values.values + kv_index * u32(m.value_bytes), value, m.value_bytes) + unsafe { + C.memcpy(m.key_values.values + kv_index * u32(m.value_bytes), value, m.value_bytes) + } return } index += 2 @@ -362,7 +374,9 @@ fn (mut m map) get_and_set(key string, zero voidptr) voidptr { if meta == m.metas[index] { kv_index := m.metas[index + 1] if fast_string_eq(key, m.key_values.keys[kv_index]) { - return voidptr(m.key_values.values + kv_index * u32(m.value_bytes)) + unsafe { + return voidptr(m.key_values.values + kv_index * u32(m.value_bytes)) + } } } index += 2 @@ -383,7 +397,9 @@ fn (m map) get(key string, zero voidptr) voidptr { if meta == m.metas[index] { kv_index := m.metas[index + 1] if fast_string_eq(key, m.key_values.keys[kv_index]) { - return voidptr(m.key_values.values + kv_index * u32(m.value_bytes)) + unsafe { + return voidptr(m.key_values.values + kv_index * u32(m.value_bytes)) + } } } index += 2 diff --git a/vlib/builtin/option.v b/vlib/builtin/option.v index db5f4d8559..7f698487c6 100644 --- a/vlib/builtin/option.v +++ b/vlib/builtin/option.v @@ -39,10 +39,10 @@ fn opt_ok2(data voidptr, mut option &OptionBase, size int) { *option = OptionBase { ok: true } - } - // use ecode to get the end of OptionBase and then memcpy into it - C.memcpy(byteptr(&option.ecode) + sizeof(int), data, size) + // use ecode to get the end of OptionBase and then memcpy into it + C.memcpy(byteptr(&option.ecode) + sizeof(int), data, size) + } } // Old option type used for bootstrapping diff --git a/vlib/builtin/sorted_map.v b/vlib/builtin/sorted_map.v index 518649d30c..0a00b9388f 100644 --- a/vlib/builtin/sorted_map.v +++ b/vlib/builtin/sorted_map.v @@ -48,7 +48,9 @@ fn new_sorted_map(n, value_bytes int) SortedMap { // TODO: Remove `n` fn new_sorted_map_init(n, value_bytes int, keys &string, values voidptr) SortedMap { mut out := new_sorted_map(n, value_bytes) for i in 0 .. n { - out.set(keys[i], byteptr(values) + i * value_bytes) + unsafe { + out.set(keys[i], byteptr(values) + i * value_bytes) + } } return out } diff --git a/vlib/builtin/utf8.v b/vlib/builtin/utf8.v index 6df511bfdd..d63aab9370 100644 --- a/vlib/builtin/utf8.v +++ b/vlib/builtin/utf8.v @@ -118,7 +118,9 @@ pub fn (_str string) to_wide() &u16 { mut wstr := &u16(malloc((num_chars + 1) * 2)) // sizeof(wchar_t) if wstr != 0 { C.MultiByteToWideChar(cp_utf8, 0, _str.str, _str.len, wstr, num_chars) - C.memset(&byte(wstr) + num_chars * 2, 0, 2) + unsafe { + C.memset(&byte(wstr) + num_chars * 2, 0, 2) + } } return wstr } $else { @@ -141,7 +143,9 @@ pub fn string_from_wide2(_wstr &u16, len int) string { mut str_to := malloc(num_chars + 1) if str_to != 0 { C.WideCharToMultiByte(cp_utf8, 0, _wstr, len, str_to, num_chars, 0, 0) - C.memset(str_to + num_chars, 0, 1) + unsafe { + C.memset(str_to + num_chars, 0, 1) + } } return tos2(str_to) } $else { diff --git a/vlib/hash/wyhash/wyhash.v b/vlib/hash/wyhash/wyhash.v index d4748b391c..7c47ba49e9 100644 --- a/vlib/hash/wyhash/wyhash.v +++ b/vlib/hash/wyhash/wyhash.v @@ -51,23 +51,25 @@ fn wyhash64(key byteptr, len, seed_ u64) u64 { mut p := &key[0] mut seed := seed_ mut i := len & 63 - if i < 4 { - seed = wymum(wyr3(p, i) ^ seed ^ wyp0, seed ^ wyp1) - } - else if i <= 8 { - seed = wymum(wyr4(p) ^ seed ^ wyp0, wyr4(p + i - 4) ^ seed ^ wyp1) - } - else if i <= 16 { - seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + i - 8) ^ seed ^ wyp1) - } - else if i <= 24 { - seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + i - 8) ^ seed ^ wyp2, seed ^ wyp3) - } - else if i <= 32 { - seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + 16) ^ seed ^ wyp2, wyr8(p + i - 8) ^ seed ^ wyp3) - } - else { - seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + 16) ^ seed ^ wyp2, wyr8(p + 24) ^ seed ^ wyp3) ^ wymum(wyr8(p + i - 32) ^ seed ^ wyp1, wyr8(p + i - 24) ^ seed ^ wyp2) ^ wymum(wyr8(p + i - 16) ^ seed ^ wyp3, wyr8(p + i - 8) ^ seed ^ wyp0) + unsafe { + if i < 4 { + seed = wymum(wyr3(p, i) ^ seed ^ wyp0, seed ^ wyp1) + } + else if i <= 8 { + seed = wymum(wyr4(p) ^ seed ^ wyp0, wyr4(p + i - 4) ^ seed ^ wyp1) + } + else if i <= 16 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + i - 8) ^ seed ^ wyp1) + } + else if i <= 24 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + i - 8) ^ seed ^ wyp2, seed ^ wyp3) + } + else if i <= 32 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + 16) ^ seed ^ wyp2, wyr8(p + i - 8) ^ seed ^ wyp3) + } + else { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + 16) ^ seed ^ wyp2, wyr8(p + 24) ^ seed ^ wyp3) ^ wymum(wyr8(p + i - 32) ^ seed ^ wyp1, wyr8(p + i - 24) ^ seed ^ wyp2) ^ wymum(wyr8(p + i - 16) ^ seed ^ wyp3, wyr8(p + i - 8) ^ seed ^ wyp0) + } } if i == len { return wymum(seed, len ^ wyp4) @@ -75,13 +77,15 @@ fn wyhash64(key byteptr, len, seed_ u64) u64 { mut see1 := seed mut see2 := seed mut see3 := seed - p = p + i - for i = len - i; i >= 64; i -= 64 { - seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) - see1 = wymum(wyr8(p + 16) ^ see1 ^ wyp2, wyr8(p + 24) ^ see1 ^ wyp3) - see2 = wymum(wyr8(p + 32) ^ see2 ^ wyp1, wyr8(p + 40) ^ see2 ^ wyp2) - see3 = wymum(wyr8(p + 48) ^ see3 ^ wyp3, wyr8(p + 56) ^ see3 ^ wyp0) - p = p + 64 + unsafe { + p = p + i + for i = len - i; i >= 64; i -= 64 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) + see1 = wymum(wyr8(p + 16) ^ see1 ^ wyp2, wyr8(p + 24) ^ see1 ^ wyp3) + see2 = wymum(wyr8(p + 32) ^ see2 ^ wyp1, wyr8(p + 40) ^ see2 ^ wyp2) + see3 = wymum(wyr8(p + 48) ^ see3 ^ wyp3, wyr8(p + 56) ^ see3 ^ wyp0) + p = p + 64 + } } return wymum(seed ^ see1 ^ see2, see3 ^ len ^ wyp4) } diff --git a/vlib/net/websocket/handshake.v b/vlib/net/websocket/handshake.v index 3982bcd176..1e3770abb2 100644 --- a/vlib/net/websocket/handshake.v +++ b/vlib/net/websocket/handshake.v @@ -7,7 +7,10 @@ fn (mut ws Client) read_handshake(seckey string) { buffer_size := 1 mut buffer := malloc(max_buffer) for bytes_read <= max_buffer { - res := ws.read_from_server(buffer + bytes_read, buffer_size) + mut res := 0 + unsafe { + res = ws.read_from_server(buffer + bytes_read, buffer_size) + } if res == 0 || res == -1 { l.f('read_handshake: Failed to read handshake.') } diff --git a/vlib/net/websocket/ws.v b/vlib/net/websocket/ws.v index 1605112029..c8fe42e52e 100644 --- a/vlib/net/websocket/ws.v +++ b/vlib/net/websocket/ws.v @@ -257,7 +257,9 @@ pub fn (mut ws Client) write(payload byteptr, payload_len int, code OPCode) int } else if payload_len > 125 && payload_len <= 0xffff { len16 := C.htons(payload_len) header[1] = (126 | 0x80) - C.memcpy(header.data + 2, &len16, 2) + unsafe { + C.memcpy(header.data + 2, &len16, 2) + } header[4] = masking_key[0] header[5] = masking_key[1] header[6] = masking_key[2] @@ -265,7 +267,9 @@ pub fn (mut ws Client) write(payload byteptr, payload_len int, code OPCode) int } else if payload_len > 0xffff && payload_len <= 0xffffffffffffffff { // 65535 && 18446744073709551615 len64 := htonl64(u64(payload_len)) header[1] = (127 | 0x80) - C.memcpy(header.data + 2, len64, 8) + unsafe { + C.memcpy(header.data + 2, len64, 8) + } header[10] = masking_key[0] header[11] = masking_key[1] header[12] = masking_key[2] @@ -276,8 +280,11 @@ pub fn (mut ws Client) write(payload byteptr, payload_len int, code OPCode) int goto free_data return -1 } - C.memcpy(fbdata, header.data, header_len) - C.memcpy(fbdata + header_len, payload, payload_len) + unsafe + { + C.memcpy(fbdata, header.data, header_len) + C.memcpy(fbdata + header_len, payload, payload_len) + } for i in 0 .. payload_len { frame_buf[header_len + i] ^= masking_key[i % 4] & 0xff } @@ -320,7 +327,10 @@ pub fn (mut ws Client) read() int { mut frame := Frame{} mut frame_size := u64(header_len) for bytes_read < frame_size && ws.state == .open { - byt := ws.read_from_server(data + int(bytes_read), 1) + mut byt := 0 + unsafe { + byt = ws.read_from_server(data + int(bytes_read), 1) + } match byt { 0 { error := 'server closed the connection.' @@ -442,7 +452,9 @@ pub fn (mut ws Client) read() int { } mut by := 0 for f in frags { - C.memcpy(pl + by, f.data, f.len) + unsafe { + C.memcpy(pl + by, f.data, f.len) + } by += int(f.len) unsafe { free(f.data) diff --git a/vlib/os/environment.v b/vlib/os/environment.v index 130c733398..bd219f6408 100644 --- a/vlib/os/environment.v +++ b/vlib/os/environment.v @@ -58,12 +58,16 @@ pub fn environ() map[string]string { $if windows { mut estrings := C.GetEnvironmentStringsW() mut eline := '' - for c := estrings; *c != 0; c = c + eline.len + 1 { + for c := estrings; *c != 0; { eline = string_from_wide(c) eq_index := eline.index_byte(`=`) if eq_index > 0 { res[eline[0..eq_index]] = eline[eq_index + 1..] } + unsafe + { + c = c + eline.len + 1 + } } C.FreeEnvironmentStringsW(estrings) } $else { diff --git a/vlib/picoev/picoev.v b/vlib/picoev/picoev.v index ffe5c6dac6..22c36741d3 100644 --- a/vlib/picoev/picoev.v +++ b/vlib/picoev/picoev.v @@ -106,12 +106,16 @@ fn close_conn(loop &C.picoev_loop, fd int) { [inline] fn myread(fd int, b byteptr, max_len, idx int) int { - return C.read(fd, b + idx, max_len - idx) + unsafe { + return C.read(fd, b + idx, max_len - idx) + } } [inline] fn mysubstr(s byteptr, from, len int) string { - return tos(s + from, len) + unsafe { + return tos(s + from, len) + } } fn rw_callback(loop &C.picoev_loop, fd, events int, cb_arg voidptr) { @@ -123,7 +127,10 @@ fn rw_callback(loop &C.picoev_loop, fd, events int, cb_arg voidptr) { } else if (events & C.PICOEV_READ) != 0 { C.picoev_set_timeout(loop, fd, timeout_secs) - buf := (p.buf + fd * max_read) + mut buf := p.buf + unsafe { + buf += fd * max_read + } idx := p.idx[fd] mut r := myread(fd, buf, max_read, idx) if r == 0 { @@ -141,12 +148,18 @@ fn rw_callback(loop &C.picoev_loop, fd, events int, cb_arg voidptr) { } else { r += idx mut s := tos(buf, r) - out := (p.out + fd * max_write) + mut out := p.out + unsafe { + out += fd * max_write + } mut res := picohttpparser.Response{ fd: fd date: p.date buf_start: out - buf: out + p.oidx[fd] + buf: out + } + unsafe { + res.buf += p.oidx[fd] } mut req := picohttpparser.Request{} for { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index fa09860eb5..2df4aa4502 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -477,6 +477,10 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type { left_default := c.table.get_type_symbol(c.table.mktyp(left_type)) left_pos := infix_expr.left.position() right_pos := infix_expr.right.position() + if (left_type.is_ptr() || left.is_pointer()) && + infix_expr.op in [.plus, .minus] && !c.inside_unsafe { + c.error('pointer arithmetic is only allowed in `unsafe` blocks', left_pos) + } mut return_type := left_type // Single side check // Place these branches according to ops' usage frequency to accelerate. diff --git a/vlib/v/tests/ptr_arithmetic_test.v b/vlib/v/tests/ptr_arithmetic_test.v index 47b8c0903b..94c1b30394 100644 --- a/vlib/v/tests/ptr_arithmetic_test.v +++ b/vlib/v/tests/ptr_arithmetic_test.v @@ -4,13 +4,13 @@ fn test_ptr_arithmetic(){ unsafe { p++ p += 2 + p = p - 1 } - p = p - 1 // not caught yet // byteptr, voidptr, charptr are handled differently mut q := byteptr(1) unsafe { q -= 2 + q = q + 1 } - q = q + 1 // not caught yet }