diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index cdba78038c..5c243da67d 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -137,7 +137,9 @@ pub fn malloc(n int) byteptr { } $if prealloc { res := g_m2_ptr - g_m2_ptr += n + unsafe { + g_m2_ptr += n + } nr_mallocs++ return res } $else { diff --git a/vlib/net/socket.v b/vlib/net/socket.v index 5c21e12253..0b58a66a45 100644 --- a/vlib/net/socket.v +++ b/vlib/net/socket.v @@ -234,7 +234,9 @@ pub fn (s Socket) send(buf byteptr, len int) ?int { if dlen <= 0 { break } - dptr += sbytes + unsafe { + dptr += sbytes + } } return len } diff --git a/vlib/picohttpparser/misc.v b/vlib/picohttpparser/misc.v index 1ed6dfafb3..2610925693 100644 --- a/vlib/picohttpparser/misc.v +++ b/vlib/picohttpparser/misc.v @@ -1,12 +1,6 @@ module picohttpparser -[inline] -fn cpy_str(dst byteptr, src string) int { - C.memcpy(dst, src.str, src.len) - return src.len -} - -[inline] +[inline] [unsafe_fn] fn cpy(dst, src byteptr, len int) int { C.memcpy(dst, src, len) return len diff --git a/vlib/picohttpparser/response.v b/vlib/picohttpparser/response.v index b8819dc74a..4e3f61fa75 100644 --- a/vlib/picohttpparser/response.v +++ b/vlib/picohttpparser/response.v @@ -9,87 +9,99 @@ pub mut: buf byteptr } +[inline] [unsafe_fn] +fn (mut r Response) write_str(s string) { + unsafe { + C.memcpy(r.buf, s.str, s.len) + r.buf += s.len + } +} + [inline] pub fn (mut r Response) http_ok() &Response { - r.buf += cpy_str(r.buf, "HTTP/1.1 200 OK\r\n") + r.write_str("HTTP/1.1 200 OK\r\n") return r } [inline] pub fn (mut r Response) header(k, v string) &Response { - r.buf += cpy_str(r.buf, k) - r.buf += cpy_str(r.buf, ": ") - r.buf += cpy_str(r.buf, v) - r.buf += cpy_str(r.buf, "\r\n") + r.write_str(k) + r.write_str(": ") + r.write_str(v) + r.write_str("\r\n") return r } [inline] pub fn (mut r Response) header_date() &Response { - r.buf += cpy_str(r.buf, "Date: ") - r.buf += cpy(r.buf, r.date, 29) - r.buf += cpy_str(r.buf, "\r\n") + r.write_str("Date: ") + unsafe { + r.buf += cpy(r.buf, r.date, 29) + } + r.write_str("\r\n") return r } [inline] pub fn (mut r Response) header_server() &Response { - r.buf += cpy_str(r.buf, "Server: V\r\n") + r.write_str("Server: V\r\n") return r } [inline] pub fn (mut r Response) content_type(s string) &Response { - r.buf += cpy_str(r.buf, "Content-Type: ") - r.buf += cpy_str(r.buf, s) - r.buf += cpy_str(r.buf, "\r\n") + r.write_str("Content-Type: ") + r.write_str(s) + r.write_str("\r\n") return r } [inline] pub fn (mut r Response) html() &Response { - r.buf += cpy_str(r.buf, "Content-Type: text/html\r\n") + r.write_str("Content-Type: text/html\r\n") return r } [inline] pub fn (mut r Response) plain() &Response { - r.buf += cpy_str(r.buf, "Content-Type: text/plain\r\n") + r.write_str("Content-Type: text/plain\r\n") return r } [inline] pub fn (mut r Response) json() &Response { - r.buf += cpy_str(r.buf, "Content-Type: application/json\r\n") + r.write_str("Content-Type: application/json\r\n") return r } [inline] pub fn (mut r Response) body(body string) { - r.buf += cpy_str(r.buf, "Content-Length: ") - r.buf += C.u64toa(r.buf, body.len) - r.buf += cpy_str(r.buf, "\r\n\r\n") - r.buf += cpy_str(r.buf, body) + r.write_str("Content-Length: ") + unsafe { + r.buf += C.u64toa(r.buf, body.len) + } + r.write_str("\r\n\r\n") + r.write_str(body) } [inline] pub fn (mut r Response) http_404() { - r.buf += cpy_str(r.buf, 'HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n') + r.write_str('HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n') } [inline] pub fn (mut r Response) http_405() { - r.buf += cpy_str(r.buf, 'HTTP/1.1 405 Method Not Allowed\r\nContent-Length: 0\r\n\r\n') + r.write_str('HTTP/1.1 405 Method Not Allowed\r\nContent-Length: 0\r\n\r\n') } [inline] pub fn (mut r Response) http_500() { - r.buf += cpy_str(r.buf, 'HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n') + r.write_str('HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n') } [inline] pub fn (mut r Response) raw(response string) { - r.buf += cpy_str(r.buf, response) + r.write_str(response) } [inline] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 0e939f61bd..7958e01cba 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1505,7 +1505,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { ast.PrefixExpr { // Do now allow `*x = y` outside `unsafe` if left.op == .mul && !c.inside_unsafe { - c.error('modifying variables via deferencing can only be done in `unsafe` blocks', + c.error('modifying variables via dereferencing can only be done in `unsafe` blocks', assign_stmt.pos) } } @@ -1515,6 +1515,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { right_type_unwrapped := c.unwrap_generic(right_type) left_sym := c.table.get_type_symbol(left_type_unwrapped) right_sym := c.table.get_type_symbol(right_type_unwrapped) + if (left_type.is_ptr() || left_sym.is_pointer()) && + assign_stmt.op !in [.assign, .decl_assign] && !c.inside_unsafe { + c.error('pointer arithmetic is only allowed in `unsafe` blocks', + assign_stmt.pos) + } // Single side check match assign_stmt.op { .assign {} // No need to do single side check for =. But here put it first for speed. @@ -2582,6 +2587,10 @@ pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type { } else { c.fail_if_immutable(node.expr) } + if (typ.is_ptr() || typ_sym.is_pointer()) && !c.inside_unsafe { + c.error('pointer arithmetic is only allowed in `unsafe` blocks', + node.pos) + } return typ } diff --git a/vlib/v/tests/ptr_arithmetic_test.v b/vlib/v/tests/ptr_arithmetic_test.v new file mode 100644 index 0000000000..47b8c0903b --- /dev/null +++ b/vlib/v/tests/ptr_arithmetic_test.v @@ -0,0 +1,16 @@ +fn test_ptr_arithmetic(){ + v := 4 + mut p := &v + unsafe { + p++ + p += 2 + } + p = p - 1 // not caught yet + + // byteptr, voidptr, charptr are handled differently + mut q := byteptr(1) + unsafe { + q -= 2 + } + q = q + 1 // not caught yet +}