checker: warn if unsafe method called outside unsafe block (#5863)

pull/5868/head
Nick Treleaven 2020-07-17 18:14:12 +01:00 committed by GitHub
parent 90d9040e6e
commit 105a0e015e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 92 additions and 9 deletions

View File

@ -331,12 +331,18 @@ pub fn (a &array) clone() array {
if a.element_size == sizeof(array) { if a.element_size == sizeof(array) {
for i in 0..a.len { for i in 0..a.len {
ar := array{} ar := array{}
C.memcpy(&ar, a.get_unsafe(i), sizeof(array)) unsafe {
C.memcpy(&ar, a.get_unsafe(i), sizeof(array))
}
ar_clone := ar.clone() ar_clone := ar.clone()
arr.set_unsafe(i, &ar_clone) unsafe {
arr.set_unsafe(i, &ar_clone)
}
} }
} else { } else {
C.memcpy(byteptr(arr.data), a.data, a.cap * a.element_size) unsafe {
C.memcpy(byteptr(arr.data), a.data, a.cap * a.element_size)
}
} }
return arr return arr
} }
@ -681,7 +687,9 @@ pub fn compare_f32(a, b &f32) int {
pub fn (a array) pointers() []voidptr { pub fn (a array) pointers() []voidptr {
mut res := []voidptr{} mut res := []voidptr{}
for i in 0..a.len { for i in 0..a.len {
res << a.get_unsafe(i) unsafe {
res << a.get_unsafe(i)
}
} }
return res return res
} }

View File

@ -517,7 +517,7 @@ pub fn (m map) clone() map {
cap: m.cap cap: m.cap
cached_hashbits: m.cached_hashbits cached_hashbits: m.cached_hashbits
shift: m.shift shift: m.shift
key_values: m.key_values.clone() key_values: unsafe {m.key_values.clone()}
metas: &u32(malloc(int(metas_size))) metas: &u32(malloc(int(metas_size)))
extra_metas: m.extra_metas extra_metas: m.extra_metas
len: m.len len: m.len

View File

@ -1201,11 +1201,14 @@ pub fn (u ustring) at(idx int) string {
return u.substr(idx, idx + 1) return u.substr(idx, idx + 1)
} }
[unsafe_fn]
fn (u &ustring) free() { fn (u &ustring) free() {
$if prealloc { $if prealloc {
return return
} }
u.runes.free() unsafe {
u.runes.free()
}
} }
pub fn (c byte) is_digit() bool { pub fn (c byte) is_digit() bool {

View File

@ -42,17 +42,22 @@ pub fn compile(command string, pref &pref.Preferences) {
println('compilation took: $sw.elapsed().milliseconds() ms') println('compilation took: $sw.elapsed().milliseconds() ms')
} }
// running does not require the parsers anymore // running does not require the parsers anymore
b.myfree() unsafe {
b.myfree()
}
if pref.is_test || pref.is_run { if pref.is_test || pref.is_run {
b.run_compiled_executable_and_exit() b.run_compiled_executable_and_exit()
} }
} }
// Temporary, will be done by -autofree // Temporary, will be done by -autofree
[unsafe_fn]
fn (mut b Builder) myfree() { fn (mut b Builder) myfree() {
// for file in b.parsed_files { // for file in b.parsed_files {
// } // }
b.parsed_files.free() unsafe {
b.parsed_files.free()
}
} }
fn (mut b Builder) run_compiled_executable_and_exit() { fn (mut b Builder) run_compiled_executable_and_exit() {

View File

@ -954,6 +954,10 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
} }
} }
} }
if method.is_unsafe && !c.inside_unsafe {
c.warn('method `${left_type_sym.name}.$method_name` must be called from an `unsafe` block',
call_expr.pos)
}
// TODO: typ optimize.. this node can get processed more than once // TODO: typ optimize.. this node can get processed more than once
if call_expr.expected_arg_types.len == 0 { if call_expr.expected_arg_types.len == 0 {
for i in 1 .. method.args.len { for i in 1 .. method.args.len {

View File

@ -123,6 +123,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
p.top_level_statement_start() p.top_level_statement_start()
start_pos := p.tok.position() start_pos := p.tok.position()
is_deprecated := 'deprecated' in p.attrs is_deprecated := 'deprecated' in p.attrs
is_unsafe := 'unsafe_fn' in p.attrs
is_pub := p.tok.kind == .key_pub is_pub := p.tok.kind == .key_pub
if is_pub { if is_pub {
p.next() p.next()
@ -250,6 +251,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_generic: is_generic is_generic: is_generic
is_pub: is_pub is_pub: is_pub
is_deprecated: is_deprecated is_deprecated: is_deprecated
is_unsafe: is_unsafe
ctdefine: ctdefine ctdefine: ctdefine
mod: p.mod mod: p.mod
attrs: p.attrs attrs: p.attrs
@ -271,12 +273,13 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
args: args args: args
return_type: return_type return_type: return_type
is_variadic: is_variadic is_variadic: is_variadic
language: language
is_generic: is_generic is_generic: is_generic
is_pub: is_pub is_pub: is_pub
is_deprecated: is_deprecated is_deprecated: is_deprecated
is_unsafe: is_unsafe
ctdefine: ctdefine ctdefine: ctdefine
mod: p.mod mod: p.mod
language: language
}) })
} }
// Body // Body

View File

@ -29,6 +29,7 @@ pub:
is_generic bool is_generic bool
is_pub bool is_pub bool
is_deprecated bool is_deprecated bool
is_unsafe bool
mod string mod string
ctdefine string // compile time define. myflag, when [if myflag] tag ctdefine string // compile time define. myflag, when [if myflag] tag
attrs []string attrs []string

View File

@ -0,0 +1,34 @@
unsafe.v:4:6: warning: pointer arithmetic is only allowed in `unsafe` blocks
2 | v := 5
3 | mut p := &v
4 | p++
| ~~
5 | p += 2
6 | _ := v
unsafe.v:5:7: warning: pointer arithmetic is only allowed in `unsafe` blocks
3 | mut p := &v
4 | p++
5 | p += 2
| ~~
6 | _ := v
7 | }
unsafe.v:11:14: warning: 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
unsafe.v:12:9: warning: pointer arithmetic is only allowed in `unsafe` blocks
10 | v := 4
11 | mut q := &v - 1
12 | q = q + 3
| ^
13 | _ := q
14 | _ := v
unsafe.v:24:7: warning: method `S1.f` must be called from an `unsafe` block
22 | fn test_funcs() {
23 | s := S1{}
24 | s.f()
| ~~~
25 | }

View File

@ -0,0 +1,25 @@
fn test_ptr_assign() {
v := 5
mut p := &v
p++
p += 2
_ := v
}
fn test_ptr_infix() {
v := 4
mut q := &v - 1
q = q + 3
_ := q
_ := v
}
struct S1 {}
[unsafe_fn]
fn (s S1) f(){}
fn test_funcs() {
s := S1{}
s.f()
}