checker: check if mut function arg is declared as mut (#5579)

pull/5586/head
Uwe Krüger 2020-06-30 14:19:22 +02:00 committed by GitHub
parent 8d7eccb8e1
commit 8a46911725
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 88 additions and 31 deletions

View File

@ -155,7 +155,7 @@ fn (mut cfg DocConfig) serve_html() {
default_filename: def_name
}
for {
con := server.accept() or {
mut con := server.accept() or {
server.close() or { }
panic(err)
}

View File

@ -16,6 +16,7 @@ pub const (
// A cipher is an instance of AES encryption using a particular key.
struct AesCipher {
mut:
enc []u32
dec []u32
}
@ -40,7 +41,7 @@ pub fn new_cipher(key []byte) AesCipher {
pub fn (c &AesCipher) block_size() int { return block_size }
pub fn (c &AesCipher) encrypt(dst, src []byte) {
pub fn (c &AesCipher) encrypt(mut dst []byte, mut src []byte) {
if src.len < block_size {
panic('crypto.aes: input not full block')
}
@ -48,23 +49,23 @@ pub fn (c &AesCipher) encrypt(dst, src []byte) {
panic('crypto.aes: output not full block')
}
// if subtle.inexact_overlap(dst[:block_size], src[:block_size]) {
if subtle.inexact_overlap(dst[..block_size], src[..block_size]) {
if subtle.inexact_overlap((*dst)[..block_size], (*src)[..block_size]) {
panic('crypto.aes: invalid buffer overlap')
}
// for now use generic version
encrypt_block_generic(c.enc, dst, src)
encrypt_block_generic(c.enc, mut dst, src)
}
pub fn (c &AesCipher) decrypt(dst, src []byte) {
pub fn (c &AesCipher) decrypt(mut dst []byte, mut src []byte) {
if src.len < block_size {
panic('crypto.aes: input not full block')
}
if dst.len < block_size {
panic('crypto.aes: output not full block')
}
if subtle.inexact_overlap(dst[..block_size], src[..block_size]) {
if subtle.inexact_overlap((*dst)[..block_size], (*src)[..block_size]) {
panic('crypto.aes: invalid buffer overlap')
}
// for now use generic version
decrypt_block_generic(c.dec, dst, src)
decrypt_block_generic(c.dec, mut dst, src)
}

View File

@ -54,7 +54,7 @@ pub fn (x &AesCbc) encrypt_blocks(mut dst []byte, src_ []byte) {
if dst.len < src.len {
panic('crypto.cipher: output smaller than input')
}
if subtle.inexact_overlap((*dst)[..src.len], src) {
if subtle.inexact_overlap((*dst)[..src.len], src_) {
panic('crypto.cipher: invalid buffer overlap')
}
@ -63,7 +63,7 @@ pub fn (x &AesCbc) encrypt_blocks(mut dst []byte, src_ []byte) {
for src.len > 0 {
// Write the xor to dst, then encrypt in place.
cipher.xor_bytes(mut (*dst)[..x.block_size], src[..x.block_size], iv)
x.b.encrypt((*dst)[..x.block_size], (*dst)[..x.block_size])
x.b.encrypt(mut (*dst)[..x.block_size], mut (*dst)[..x.block_size])
// Move to the next block with this block as the next iv.
iv = (*dst)[..x.block_size]
@ -104,7 +104,7 @@ pub fn (mut x AesCbc) decrypt_blocks(mut dst []byte, src []byte) {
// Loop over all but the first block.
for start > 0 {
x.b.decrypt((*dst).slice(start, end), src.slice(start, end))
x.b.decrypt(mut (*dst).slice(start, end), mut src.slice(start, end))
cipher.xor_bytes(mut (*dst).slice(start, end), (*dst).slice(start, end), src.slice(prev, start))
end = start
@ -113,7 +113,7 @@ pub fn (mut x AesCbc) decrypt_blocks(mut dst []byte, src []byte) {
}
// The first block is special because it uses the saved iv.
x.b.decrypt((*dst).slice(start, end), src.slice(start, end))
x.b.decrypt(mut (*dst).slice(start, end), mut src.slice(start, end))
cipher.xor_bytes(mut (*dst).slice(start, end), (*dst).slice(start, end), x.iv)

View File

@ -40,7 +40,7 @@ module aes
import encoding.binary
// Encrypt one block from src into dst, using the expanded key xk.
fn encrypt_block_generic(xk []u32, dst, src []byte) {
fn encrypt_block_generic(xk []u32, mut dst []byte, src []byte) {
_ = src[15] // early bounds check
mut s0 := binary.big_endian_u32(src[..4])
mut s1 := binary.big_endian_u32(src.slice(4, 8))
@ -85,16 +85,16 @@ fn encrypt_block_generic(xk []u32, dst, src []byte) {
s3 ^= xk[k+3]
_ := dst[15] // early bounds check
binary.big_endian_put_u32(mut dst[..4], s0)
binary.big_endian_put_u32(mut dst.slice(4, 8), s1)
binary.big_endian_put_u32(mut dst.slice(8, 12), s2)
binary.big_endian_put_u32(mut dst.slice(12, 16), s3)
binary.big_endian_put_u32(mut (*dst)[0..4], s0)
binary.big_endian_put_u32(mut (*dst).slice(4, 8), s1)
binary.big_endian_put_u32(mut (*dst).slice(8, 12), s2)
binary.big_endian_put_u32(mut (*dst).slice(12, 16), s3)
}
// Decrypt one block from src into dst, using the expanded key xk.
fn decrypt_block_generic(xk []u32, dst, src []byte) {
fn decrypt_block_generic(xk []u32, mut dst []byte, src []byte) {
_ = src[15] // early bounds check
mut s0 := binary.big_endian_u32(src[..4])
mut s0 := binary.big_endian_u32(src[0..4])
mut s1 := binary.big_endian_u32(src.slice(4, 8))
mut s2 := binary.big_endian_u32(src.slice(8, 12))
mut s3 := binary.big_endian_u32(src.slice(12, 16))
@ -137,10 +137,10 @@ fn decrypt_block_generic(xk []u32, dst, src []byte) {
s3 ^= xk[k+3]
_ = dst[15] // early bounds check
binary.big_endian_put_u32(mut dst[..4], s0)
binary.big_endian_put_u32(mut dst.slice(4, 8), s1)
binary.big_endian_put_u32(mut dst.slice(8, 12), s2)
binary.big_endian_put_u32(mut dst.slice(12, 16), s3)
binary.big_endian_put_u32(mut (*dst)[..4], s0)
binary.big_endian_put_u32(mut (*dst).slice(4, 8), s1)
binary.big_endian_put_u32(mut (*dst).slice(8, 12), s2)
binary.big_endian_put_u32(mut (*dst).slice(12, 16), s3)
}
// Apply s_box0 to each byte in w.

View File

@ -117,7 +117,7 @@ pub fn (mut d Digest) checksum() []byte {
panic('d.nx != 0')
}
digest := []byte{len:(size)}
mut digest := []byte{len:(size)}
binary.little_endian_put_u32(mut digest, d.s[0])
binary.little_endian_put_u32(mut digest[4..], d.s[1])

View File

@ -59,7 +59,7 @@ pub fn (mut c Cipher) reset() {
// xor_key_stream sets dst to the result of XORing src with the key stream.
// Dst and src must overlap entirely or not at all.
pub fn (mut c Cipher) xor_key_stream(mut dst []byte, src []byte) {
pub fn (mut c Cipher) xor_key_stream(mut dst, src []byte) {
if src.len == 0 {
return
}

View File

@ -161,7 +161,7 @@ fn (mut d Digest) checksum() []byte {
panic('d.nx != 0')
}
digest := []byte{len:(size)}
mut digest := []byte{len:(size)}
binary.big_endian_put_u32(mut digest, d.h[0])
binary.big_endian_put_u32(mut digest[4..], d.h[1])

View File

@ -690,6 +690,17 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) {
}
}
}
ast.CallExpr {
// TODO: should only work for builtin method
if expr.name == 'slice' {
return
} else {
c.error('cannot use function call as mut', expr.pos)
}
}
ast.ArrayInit {
return
}
else {
c.error('unexpected expression `${typeof(expr)}`', expr.position())
}
@ -1097,11 +1108,16 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
c.error('when forwarding a varg variable, it must be the final argument',
call_expr.pos)
}
if arg.is_mut && !call_arg.is_mut {
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
call_arg.expr.position())
} else if !arg.is_mut && call_arg.is_mut {
c.error('`$arg.name` argument is not mutable, `mut` is not needed`', call_arg.expr.position())
if call_arg.is_mut {
c.fail_if_immutable(call_arg.expr)
if !arg.is_mut {
c.error('`$arg.name` argument is not mutable, `mut` is not needed`', call_arg.expr.position())
}
} else {
if arg.is_mut {
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
call_arg.expr.position())
}
}
// Handle expected interface
if arg_typ_sym.kind == .interface_ {

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/immutable_arg.v:13:8: error: `a` is immutable, declare it with `mut` to make it mutable
11 | fn main() {
12 | a := St{e: 2}
13 | f(mut a)
| ^
14 | }

View File

@ -0,0 +1,14 @@
struct St {
mut:
e int
}
fn f(mut x St) {
x.e++
println(x)
}
fn main() {
a := St{e: 2}
f(mut a)
}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/immutable_rec.v:13:2: error: `a` is immutable, declare it with `mut` to make it mutable
11 | fn main() {
12 | a := St{e: 2}
13 | a.f()
| ^
14 | }

View File

@ -0,0 +1,14 @@
struct St {
mut:
e int
}
fn (mut x St) f() {
x.e++
println(x)
}
fn main() {
a := St{e: 2}
a.f()
}

View File

@ -77,7 +77,7 @@ fn mut_arg2<T>(mut x T) T {
fn test_create() {
create<User>()
create<City>()
u := User{}
mut u := User{}
mut_arg<User>(mut u)
mut_arg2<User>(mut u)
}