From 5f07b255bd65edbb215a9a9311f08a50b494d9e5 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Mon, 5 Oct 2020 16:38:30 +0530 Subject: [PATCH] checker: disallow address of array and map index outside unsafe (#6557) --- vlib/cli/command.v | 2 ++ vlib/crypto/internal/subtle/aliasing.v | 6 +++--- vlib/regex/regex.v | 2 +- vlib/strconv/f32_str.v | 4 +++- vlib/strconv/f64_str.v | 4 +++- vlib/sync/channels.v | 14 +++++++++---- vlib/v/builder/generics.v | 2 +- vlib/v/checker/checker.v | 29 +++++++++++++++++++------- vlib/v/compiler_errors_test.v | 4 +++- vlib/v/gen/cgen.v | 2 +- vlib/v/table/table.v | 8 +++---- vlib/v/tests/unsafe_test.v | 2 +- 12 files changed, 54 insertions(+), 25 deletions(-) diff --git a/vlib/cli/command.v b/vlib/cli/command.v index 585b614155..b6a017af06 100644 --- a/vlib/cli/command.v +++ b/vlib/cli/command.v @@ -148,6 +148,7 @@ fn (mut cmd Command) parse_flags() { } mut found := false for i in 0 .. cmd.flags.len { + unsafe { mut flag := &cmd.flags[i] if flag.matches(cmd.args, cmd.flags.have_abbrev()) { found = true @@ -158,6 +159,7 @@ fn (mut cmd Command) parse_flags() { } break } + } } if !found { println('Command `$cmd.name` has no flag `${cmd.args[0]}`') diff --git a/vlib/crypto/internal/subtle/aliasing.v b/vlib/crypto/internal/subtle/aliasing.v index d4cb50333e..aaa80f155b 100644 --- a/vlib/crypto/internal/subtle/aliasing.v +++ b/vlib/crypto/internal/subtle/aliasing.v @@ -16,8 +16,8 @@ pub fn any_overlap(x, y []byte) bool { return x.len > 0 && y.len > 0 && // &x.data[0] <= &y.data[y.len-1] && // &y.data[0] <= &x.data[x.len-1] - &x[0] <= &y[y.len-1] && - &y[0] <= &x[x.len-1] + unsafe { &x[0] <= &y[y.len-1] && + &y[0] <= &x[x.len-1] } } // inexact_overlap reports whether x and y share memory at any non-corresponding @@ -27,7 +27,7 @@ pub fn any_overlap(x, y []byte) bool { // inexact_overlap can be used to implement the requirements of the crypto/cipher // AEAD, Block, BlockMode and Stream interfaces. pub fn inexact_overlap(x, y []byte) bool { - if x.len == 0 || y.len == 0 || &x[0] == &y[0] { + if x.len == 0 || y.len == 0 || unsafe { &x[0] == &y[0] } { return false } return any_overlap(x, y) diff --git a/vlib/regex/regex.v b/vlib/regex/regex.v index 5724db0d83..5f62d9438f 100644 --- a/vlib/regex/regex.v +++ b/vlib/regex/regex.v @@ -1346,7 +1346,7 @@ pub fn (re RE) get_query() string { mut i := 0 for i < re.prog.len && re.prog[i].ist != ist_prog_end && re.prog[i].ist != 0{ - tk := &re.prog[i] + tk := unsafe { &re.prog[i] } ch := tk.ist // GROUP start diff --git a/vlib/strconv/f32_str.v b/vlib/strconv/f32_str.v index aaa6d64dff..353b4a08d4 100644 --- a/vlib/strconv/f32_str.v +++ b/vlib/strconv/f32_str.v @@ -160,7 +160,9 @@ pub fn (d Dec32) get_string_32(neg bool, i_n_digit int, i_pad_digit int) string x++ } */ - return tos(byteptr(&buf[0]), i) + return unsafe { + tos(byteptr(&buf[0]), i) + } } fn f32_to_decimal_exact_int(i_mant u32, exp u32) (Dec32,bool) { diff --git a/vlib/strconv/f64_str.v b/vlib/strconv/f64_str.v index 0da50bf595..b9aee66f80 100644 --- a/vlib/strconv/f64_str.v +++ b/vlib/strconv/f64_str.v @@ -190,7 +190,9 @@ fn (d Dec64) get_string_64(neg bool, i_n_digit int, i_pad_digit int) string { x++ } */ - return tos(byteptr(&buf[0]), i) + return unsafe { + tos(byteptr(&buf[0]), i) + } } fn f64_to_decimal_exact_int(i_mant u64, exp u64) (Dec64, bool) { diff --git a/vlib/sync/channels.v b/vlib/sync/channels.v index 86baad2bcd..721717cedc 100644 --- a/vlib/sync/channels.v +++ b/vlib/sync/channels.v @@ -514,9 +514,13 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo } subscr[i].sem = sem subscr[i].prev = &ch.write_subscriber - subscr[i].nxt = C.atomic_exchange_ptr(&ch.write_subscriber, &subscr[i]) + unsafe { + subscr[i].nxt = C.atomic_exchange_ptr(&ch.write_subscriber, &subscr[i]) + } if voidptr(subscr[i].nxt) != voidptr(0) { - subscr[i].nxt.prev = &subscr[i] + unsafe { + subscr[i].nxt.prev = &subscr[i] + } } C.atomic_store_u16(&ch.write_sub_mtx, u16(0)) } else { @@ -526,9 +530,11 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo } subscr[i].sem = sem subscr[i].prev = &ch.read_subscriber - subscr[i].nxt = C.atomic_exchange_ptr(&ch.read_subscriber, &subscr[i]) + unsafe { + subscr[i].nxt = C.atomic_exchange_ptr(&ch.read_subscriber, &subscr[i]) + } if voidptr(subscr[i].nxt) != voidptr(0) { - subscr[i].nxt.prev = &subscr[i] + unsafe { subscr[i].nxt.prev = &subscr[i] } } C.atomic_store_u16(&ch.read_sub_mtx, u16(0)) } diff --git a/vlib/v/builder/generics.v b/vlib/v/builder/generics.v index 816eac40a2..491e526fa3 100644 --- a/vlib/v/builder/generics.v +++ b/vlib/v/builder/generics.v @@ -5,7 +5,7 @@ import v.table // generic struct instantiations to concrete types pub fn (b &Builder) generic_struct_insts_to_concrete() { for idx, _ in b.table.types { - mut typ := &b.table.types[idx] + mut typ := unsafe { &b.table.types[idx] } if typ.kind == .generic_struct_inst { info := typ.info as table.GenericStructInst parent := b.table.types[info.parent_idx] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index ee7c121f74..e71fe8a03b 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -123,13 +123,15 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) { mut has_main_fn := false mut files_from_main_module := []&ast.File{} for i in 0 .. ast_files.len { - file := &ast_files[i] - c.check(file) - if file.mod.name == 'main' { - files_from_main_module << file - has_main_mod_file = true - if c.check_file_in_main(file) { - has_main_fn = true + unsafe { + file := &ast_files[i] + c.check(file) + if file.mod.name == 'main' { + files_from_main_module << file + has_main_mod_file = true + if c.check_file_in_main(file) { + has_main_fn = true + } } } } @@ -2746,6 +2748,19 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { if node.right is ast.StringLiteral || node.right is ast.StringInterLiteral { c.error('cannot take the address of a string', node.pos) } + if node.right is ast.IndexExpr as index { + typ_sym := c.table.get_type_symbol(index.left_type) + if !c.inside_unsafe { + if typ_sym.kind == .map { + c.error('cannot get address of map values outside unsafe blocks', + index.pos) + } + if typ_sym.kind == .array { + c.error('cannot get address of array elements outside unsafe blocks', + index.pos) + } + } + } return right_type.to_ptr() } if node.op == .mul { diff --git a/vlib/v/compiler_errors_test.v b/vlib/v/compiler_errors_test.v index 7c5bea9eaf..d3e831250c 100644 --- a/vlib/v/compiler_errors_test.v +++ b/vlib/v/compiler_errors_test.v @@ -88,7 +88,9 @@ fn (mut tasks []TaskDescription) run() { if tasks[i].path in m_skip_files { tasks[i].is_skipped = true } - work.push(&tasks[i]) + unsafe { + work.push(&tasks[i]) + } } work.close() for _ in 0 .. vjobs { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 108ae6bda5..128c27fbb6 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -534,7 +534,7 @@ typedef struct { for typ in g.table.types { match typ.kind { .alias { - parent := &g.table.types[typ.parent_idx] + parent := unsafe {&g.table.types[typ.parent_idx]} styp := util.no_dots(typ.name) is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.` parent_styp := if is_c_parent { 'struct ' + util.no_dots(parent.name[2..]) } else { util.no_dots(parent.name) } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index b183895fc5..d4317f8d93 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -211,7 +211,7 @@ pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn { if ts.parent_idx == 0 { break } - ts = &t.types[ts.parent_idx] + ts = unsafe { &t.types[ts.parent_idx] } } return none } @@ -270,7 +270,7 @@ pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field { if ts.parent_idx == 0 { break } - ts = &t.types[ts.parent_idx] + ts = unsafe { &t.types[ts.parent_idx] } } return none } @@ -294,7 +294,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol { // println('get_type_symbol $typ') idx := typ.idx() if idx > 0 { - return &t.types[idx] + return unsafe{ &t.types[idx] } } // this should never happen panic('get_type_symbol: invalid type (typ=$typ idx=$idx). Compiler bug. This should never happen') @@ -310,7 +310,7 @@ pub fn (t &Table) get_final_type_symbol(typ Type) &TypeSymbol { alias_info := current_type.info as Alias return t.get_final_type_symbol(alias_info.parent_type) } - return &t.types[idx] + return unsafe { &t.types[idx] } } // this should never happen panic('get_final_type_symbol: invalid type (typ=$typ idx=$idx). Compiler bug. This should never happen') diff --git a/vlib/v/tests/unsafe_test.v b/vlib/v/tests/unsafe_test.v index c3500d2525..1391c3ce9f 100644 --- a/vlib/v/tests/unsafe_test.v +++ b/vlib/v/tests/unsafe_test.v @@ -1,7 +1,7 @@ fn test_ptr_assign() { v := [int(5), 6, 77, 1] - mut p := &v[0] unsafe { + mut p := &v[0] (*p)++ p++ // p now points to v[1] (*p) += 2