all: disallow pointer arithmetic for AssignStmt, PostfixExpr outside unsafe{} (#5581)

pull/5604/head
Nick Treleaven 2020-07-01 13:50:17 +01:00 committed by GitHub
parent 5eb76606ae
commit e7339fec15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 33 deletions

View File

@ -137,7 +137,9 @@ pub fn malloc(n int) byteptr {
} }
$if prealloc { $if prealloc {
res := g_m2_ptr res := g_m2_ptr
g_m2_ptr += n unsafe {
g_m2_ptr += n
}
nr_mallocs++ nr_mallocs++
return res return res
} $else { } $else {

View File

@ -234,7 +234,9 @@ pub fn (s Socket) send(buf byteptr, len int) ?int {
if dlen <= 0 { if dlen <= 0 {
break break
} }
dptr += sbytes unsafe {
dptr += sbytes
}
} }
return len return len
} }

View File

@ -1,12 +1,6 @@
module picohttpparser module picohttpparser
[inline] [inline] [unsafe_fn]
fn cpy_str(dst byteptr, src string) int {
C.memcpy(dst, src.str, src.len)
return src.len
}
[inline]
fn cpy(dst, src byteptr, len int) int { fn cpy(dst, src byteptr, len int) int {
C.memcpy(dst, src, len) C.memcpy(dst, src, len)
return len return len

View File

@ -9,87 +9,99 @@ pub mut:
buf byteptr 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] [inline]
pub fn (mut r Response) http_ok() &Response { 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 return r
} }
[inline] [inline]
pub fn (mut r Response) header(k, v string) &Response { pub fn (mut r Response) header(k, v string) &Response {
r.buf += cpy_str(r.buf, k) r.write_str(k)
r.buf += cpy_str(r.buf, ": ") r.write_str(": ")
r.buf += cpy_str(r.buf, v) r.write_str(v)
r.buf += cpy_str(r.buf, "\r\n") r.write_str("\r\n")
return r return r
} }
[inline] [inline]
pub fn (mut r Response) header_date() &Response { pub fn (mut r Response) header_date() &Response {
r.buf += cpy_str(r.buf, "Date: ") r.write_str("Date: ")
r.buf += cpy(r.buf, r.date, 29) unsafe {
r.buf += cpy_str(r.buf, "\r\n") r.buf += cpy(r.buf, r.date, 29)
}
r.write_str("\r\n")
return r return r
} }
[inline] [inline]
pub fn (mut r Response) header_server() &Response { 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 return r
} }
[inline] [inline]
pub fn (mut r Response) content_type(s string) &Response { pub fn (mut r Response) content_type(s string) &Response {
r.buf += cpy_str(r.buf, "Content-Type: ") r.write_str("Content-Type: ")
r.buf += cpy_str(r.buf, s) r.write_str(s)
r.buf += cpy_str(r.buf, "\r\n") r.write_str("\r\n")
return r return r
} }
[inline] [inline]
pub fn (mut r Response) html() &Response { 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 return r
} }
[inline] [inline]
pub fn (mut r Response) plain() &Response { 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 return r
} }
[inline] [inline]
pub fn (mut r Response) json() &Response { 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 return r
} }
[inline] [inline]
pub fn (mut r Response) body(body string) { pub fn (mut r Response) body(body string) {
r.buf += cpy_str(r.buf, "Content-Length: ") r.write_str("Content-Length: ")
r.buf += C.u64toa(r.buf, body.len) unsafe {
r.buf += cpy_str(r.buf, "\r\n\r\n") r.buf += C.u64toa(r.buf, body.len)
r.buf += cpy_str(r.buf, body) }
r.write_str("\r\n\r\n")
r.write_str(body)
} }
[inline] [inline]
pub fn (mut r Response) http_404() { 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] [inline]
pub fn (mut r Response) http_405() { 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] [inline]
pub fn (mut r Response) http_500() { 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] [inline]
pub fn (mut r Response) raw(response string) { pub fn (mut r Response) raw(response string) {
r.buf += cpy_str(r.buf, response) r.write_str(response)
} }
[inline] [inline]

View File

@ -1505,7 +1505,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
ast.PrefixExpr { ast.PrefixExpr {
// Do now allow `*x = y` outside `unsafe` // Do now allow `*x = y` outside `unsafe`
if left.op == .mul && !c.inside_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) 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) right_type_unwrapped := c.unwrap_generic(right_type)
left_sym := c.table.get_type_symbol(left_type_unwrapped) left_sym := c.table.get_type_symbol(left_type_unwrapped)
right_sym := c.table.get_type_symbol(right_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 // Single side check
match assign_stmt.op { match assign_stmt.op {
.assign {} // No need to do single side check for =. But here put it first for speed. .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 { } else {
c.fail_if_immutable(node.expr) 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 return typ
} }

View File

@ -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
}