From d785e22a6ea4216dd6f7c54eba3032691a0374ff Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 12 Dec 2020 09:42:07 +0000 Subject: [PATCH] checker: disallow assigning number to pointer (#7267) --- vlib/builtin/builtin_nix.c.v | 2 +- vlib/builtin/builtin_windows.c.v | 2 +- vlib/clipboard/clipboard_linux.c.v | 4 +--- vlib/live/executable/reloader.v | 2 +- vlib/v/checker/check_types.v | 7 +++++- vlib/v/checker/checker.v | 35 ++++++++++++++++++----------- vlib/v/checker/tests/ptr_assign.out | 5 +++++ vlib/v/checker/tests/ptr_assign.vv | 3 +++ vlib/v/gen/js/js.v | 4 ++-- vlib/v/tests/interop_test.v | 5 +++++ 10 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 vlib/v/checker/tests/ptr_assign.out create mode 100644 vlib/v/checker/tests/ptr_assign.vv diff --git a/vlib/builtin/builtin_nix.c.v b/vlib/builtin/builtin_nix.c.v index c14a3ae302..7892ddb4a1 100644 --- a/vlib/builtin/builtin_nix.c.v +++ b/vlib/builtin/builtin_nix.c.v @@ -140,6 +140,6 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { fn break_if_debugger_attached() { unsafe { mut ptr := &voidptr(0) - *ptr = 0 + *ptr = voidptr(0) } } diff --git a/vlib/builtin/builtin_windows.c.v b/vlib/builtin/builtin_windows.c.v index fb74c0c0c6..7be88f9029 100644 --- a/vlib/builtin/builtin_windows.c.v +++ b/vlib/builtin/builtin_windows.c.v @@ -234,7 +234,7 @@ fn break_if_debugger_attached() { $if tinyc { unsafe { mut ptr := &voidptr(0) - *ptr = 0 + *ptr = voidptr(0) } } $else { if C.IsDebuggerPresent() { diff --git a/vlib/clipboard/clipboard_linux.c.v b/vlib/clipboard/clipboard_linux.c.v index 37a786be79..b15606b663 100644 --- a/vlib/clipboard/clipboard_linux.c.v +++ b/vlib/clipboard/clipboard_linux.c.v @@ -425,9 +425,7 @@ fn (cb &Clipboard) get_supported_targets() []C.Atom { } fn new_atom(value int) &C.Atom { - mut atom := &C.Atom{} - atom = value - return atom + return unsafe {&C.Atom(value)} } fn create_xwindow(display &C.Display) C.Window { diff --git a/vlib/live/executable/reloader.v b/vlib/live/executable/reloader.v index 62f18ccf5d..ffcab1faf4 100644 --- a/vlib/live/executable/reloader.v +++ b/vlib/live/executable/reloader.v @@ -118,7 +118,7 @@ fn load_lib(mut r live.LiveReloadInfo, new_lib_path string) { fn protected_load_lib(mut r live.LiveReloadInfo, new_lib_path string) { if r.live_lib != 0 { dl.close( r.live_lib ) - r.live_lib = 0 + r.live_lib = C.NULL } r.live_lib = dl.open(new_lib_path, dl.rtld_lazy) if r.live_lib == 0 { diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 7c808eb5a3..6e0db4c0fc 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -283,9 +283,14 @@ pub fn (mut c Checker) check_expected(got table.Type, expected table.Type) ? { if c.check_types(got, expected) { return } + return error(c.expected_msg(got, expected)) +} + +[inline] +fn (c &Checker) expected_msg(got table.Type, expected table.Type) string { exps := c.table.type_to_str(expected) gots := c.table.type_to_str(got) - return error('expected `$exps`, not `$gots`') + return 'expected `$exps`, not `$gots`' } pub fn (mut c Checker) symmetric_check(left table.Type, right table.Type) bool { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 43afd8108e..856781a98c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2173,25 +2173,31 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { } left_sym := c.table.get_type_symbol(left_type_unwrapped) right_sym := c.table.get_type_symbol(right_type_unwrapped) - left_is_ptr := left_type.is_ptr() || left_sym.is_pointer() - right_is_ptr := right_type.is_ptr() || right_sym.is_pointer() - if left_is_ptr && assign_stmt.op !in [.assign, .decl_assign] && !c.inside_unsafe { - // ptr op= - c.warn('pointer arithmetic is only allowed in `unsafe` blocks', assign_stmt.pos) - } if c.pref.translated { // TODO fix this in C2V instead, for example cast enums to int before using `|` on them. // TODO replace all c.pref.translated checks with `$if !translated` for performance continue } - if left_is_ptr && (right is ast.StructInit || !right_is_ptr) && !right_sym.is_number() { - left_name := c.table.type_to_str(left_type_unwrapped) - mut rtype := right_type_unwrapped - if rtype.is_ptr() { - rtype = rtype.deref() + left_is_ptr := left_type.is_ptr() || left_sym.is_pointer() + if left_is_ptr { + if !c.inside_unsafe && assign_stmt.op !in [.assign, .decl_assign] { + // ptr op= + c.warn('pointer arithmetic is only allowed in `unsafe` blocks', assign_stmt.pos) + } + right_is_ptr := right_type.is_ptr() || right_sym.is_pointer() + if !right_is_ptr && assign_stmt.op == .assign && right_type_unwrapped.is_number() { + c.error('cannot assign to `$left`: ' + + c.expected_msg(right_type_unwrapped, left_type_unwrapped), right.position()) + } + if (right is ast.StructInit || !right_is_ptr) && !right_sym.is_number() { + left_name := c.table.type_to_str(left_type_unwrapped) + mut rtype := right_type_unwrapped + if rtype.is_ptr() { + rtype = rtype.deref() + } + right_name := c.table.type_to_str(rtype) + c.error('mismatched types `$left_name` and `$right_name`', assign_stmt.pos) } - right_name := c.table.type_to_str(rtype) - c.error('mismatched types `$left_name` and `$right_name`', assign_stmt.pos) } // Single side check match assign_stmt.op { @@ -3364,6 +3370,9 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type { } } if ident.language == .c { + if ident.name == 'C.NULL' { + return table.voidptr_type + } return table.int_type } if c.inside_sql { diff --git a/vlib/v/checker/tests/ptr_assign.out b/vlib/v/checker/tests/ptr_assign.out new file mode 100644 index 0000000000..a8675578c6 --- /dev/null +++ b/vlib/v/checker/tests/ptr_assign.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/ptr_assign.vv:3:5: error: cannot assign to `p`: expected `&int`, not `any_int` + 1 | mut v := 43 + 2 | mut p := &v + 3 | p = 4 + | ^ diff --git a/vlib/v/checker/tests/ptr_assign.vv b/vlib/v/checker/tests/ptr_assign.vv new file mode 100644 index 0000000000..1b8cbe456b --- /dev/null +++ b/vlib/v/checker/tests/ptr_assign.vv @@ -0,0 +1,3 @@ +mut v := 43 +mut p := &v +p = 4 diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index d15a4cbae1..7b8fcf23d6 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -193,7 +193,7 @@ pub fn (mut g JsGen) enter_namespace(name string) { } pub fn (mut g JsGen) escape_namespace() { - g.ns = 0 + g.ns = &Namespace(0) g.inside_builtin = false } @@ -1535,4 +1535,4 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) { if !is_literal { g.write(')') } -} \ No newline at end of file +} diff --git a/vlib/v/tests/interop_test.v b/vlib/v/tests/interop_test.v index 6d13d872be..e37bc131fb 100644 --- a/vlib/v/tests/interop_test.v +++ b/vlib/v/tests/interop_test.v @@ -14,3 +14,8 @@ fn JS.f(a &Foo) // TODO: Should this be allowed? fn C.g(string, ...int) fn C.h(&int) fn JS.i(...string) + +fn test_null() { + np := C.NULL + assert typeof(np).name == 'voidptr' +}