From 3d99f1f2c2a08f771ba54102348f71381b840f5e Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Thu, 13 Apr 2023 11:08:21 +0530 Subject: [PATCH] checker: disallow struct int to ptr outside unsafe (#17923) --- cmd/tools/vpm.v | 2 +- doc/docs.md | 4 +-- .../sokol/particles/modules/particle/system.v | 4 +-- vlib/builtin/sorted_map.v | 4 +-- vlib/db/mysql/stmt.c.v | 2 +- vlib/db/sqlite/sqlite.v | 10 +++---- vlib/db/sqlite/stmt.v | 2 +- vlib/db/sqlite/vfs_lowlevel.v | 2 +- vlib/dlmalloc/dlmalloc.v | 2 +- vlib/net/address.v | 2 +- vlib/net/common.v | 2 +- vlib/net/mbedtls/ssl_connection.v | 2 +- vlib/net/openssl/openssl_compiles_test.v | 2 +- vlib/net/openssl/ssl_connection.v | 2 +- vlib/net/unix/common.v | 2 +- vlib/os/os_nix.c.v | 2 +- vlib/sqlite/sqlite.v | 10 +++---- vlib/sqlite/vfs_lowlevel.v | 2 +- vlib/term/ui/input_nix.c.v | 2 +- vlib/term/ui/input_windows.c.v | 2 +- vlib/term/ui/termios_nix.c.v | 4 +-- vlib/toml/tests/toml_bom_test.v | 2 +- vlib/v/ast/table.v | 2 +- vlib/v/checker/checker.v | 27 ++++++++++++++++++- ...struct_ptr_cast_int_outside_unsafe_err.out | 18 +++++++++++++ .../struct_ptr_cast_int_outside_unsafe_err.vv | 8 ++++++ .../tests/struct_ptr_cast_zero_err.out | 18 +++++++++++++ .../checker/tests/struct_ptr_cast_zero_err.vv | 8 ++++++ vlib/v/gen/js/js.v | 2 +- vlib/v/parser/parser.v | 2 +- vlib/v/pkgconfig/main.v | 2 +- vlib/v/tests/cast_to_alias_test.v | 4 +-- vlib/v/token/keywords_matcher_trie.v | 2 +- vlib/v/util/util.v | 4 +-- vlib/vweb/tests/middleware_test.v | 4 +-- vlib/vweb/tests/vweb_test.v | 2 +- 36 files changed, 124 insertions(+), 47 deletions(-) create mode 100644 vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.out create mode 100644 vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv create mode 100644 vlib/v/checker/tests/struct_ptr_cast_zero_err.out create mode 100644 vlib/v/checker/tests/struct_ptr_cast_zero_err.vv diff --git a/cmd/tools/vpm.v b/cmd/tools/vpm.v index 2838b91b0a..d1739c394b 100644 --- a/cmd/tools/vpm.v +++ b/cmd/tools/vpm.v @@ -704,7 +704,7 @@ const ( ) fn init_settings() { - mut s := &VpmSettings(0) + mut s := &VpmSettings(unsafe { nil }) unsafe { s = settings } diff --git a/doc/docs.md b/doc/docs.md index 264be94fc1..4a79fb0d6c 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -6188,12 +6188,12 @@ fn my_callback(arg voidptr, howmany int, cvalues &&char, cnames &&char) int { } fn main() { - db := &C.sqlite3(0) // this means `sqlite3* db = 0` + db := &C.sqlite3(unsafe { nil }) // this means `sqlite3* db = 0` // passing a string literal to a C function call results in a C string, not a V string C.sqlite3_open(c'users.db', &db) // C.sqlite3_open(db_path.str, &db) query := 'select count(*) from users' - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) // Note: You can also use the `.str` field of a V string, // to get its C style zero terminated representation C.sqlite3_prepare_v2(db, &char(query.str), -1, &stmt, 0) diff --git a/examples/sokol/particles/modules/particle/system.v b/examples/sokol/particles/modules/particle/system.v index dba4081976..c6035cc443 100644 --- a/examples/sokol/particles/modules/particle/system.v +++ b/examples/sokol/particles/modules/particle/system.v @@ -28,7 +28,7 @@ pub fn (mut s System) init(sc SystemConfig) { } pub fn (mut s System) update(dt f64) { - mut p := &Particle(0) + mut p := &Particle(unsafe { nil }) mut moved := 0 for i := 0; i < s.pool.len; i++ { p = s.pool[i] @@ -70,7 +70,7 @@ pub fn (mut s System) reset() { pub fn (mut s System) explode(x f32, y f32) { mut reserve := 500 center := vec.Vec2[f64]{x, y} - mut p := &Particle(0) + mut p := &Particle(unsafe { nil }) mut moved := 0 for i := 0; i < s.bin.len && reserve > 0; i++ { p = s.bin[i] diff --git a/vlib/builtin/sorted_map.v b/vlib/builtin/sorted_map.v index 941bd37b98..04bd6d2d57 100644 --- a/vlib/builtin/sorted_map.v +++ b/vlib/builtin/sorted_map.v @@ -70,7 +70,7 @@ fn new_node() &mapnode { fn (mut m SortedMap) set(key string, value voidptr) { mut node := m.root mut child_index := 0 - mut parent := &mapnode(0) + mut parent := &mapnode(unsafe { nil }) for { if node.len == max_len { if parent == unsafe { nil } { @@ -228,7 +228,7 @@ fn (mut n mapnode) remove_key(k string) bool { n.fill(idx) } - mut node := &mapnode(0) + mut node := &mapnode(unsafe { nil }) if flag && idx > n.len { node = unsafe { &mapnode(n.children[idx - 1]) } } else { diff --git a/vlib/db/mysql/stmt.c.v b/vlib/db/mysql/stmt.c.v index 4e6233e23b..162db2981c 100644 --- a/vlib/db/mysql/stmt.c.v +++ b/vlib/db/mysql/stmt.c.v @@ -63,7 +63,7 @@ fn C.mysql_stmt_next_result(&C.MYSQL_STMT) int fn C.mysql_stmt_store_result(&C.MYSQL_STMT) int pub struct Stmt { - stmt &C.MYSQL_STMT = &C.MYSQL_STMT(0) + stmt &C.MYSQL_STMT = &C.MYSQL_STMT(unsafe { nil }) query string mut: binds []C.MYSQL_BIND diff --git a/vlib/db/sqlite/sqlite.v b/vlib/db/sqlite/sqlite.v index 7a95cc9ff5..ec6e254f55 100644 --- a/vlib/db/sqlite/sqlite.v +++ b/vlib/db/sqlite/sqlite.v @@ -127,7 +127,7 @@ fn C.sqlite3_changes(&C.sqlite3) int // connect Opens the connection with a database. pub fn connect(path string) !DB { - db := &C.sqlite3(0) + db := &C.sqlite3(unsafe { nil }) code := C.sqlite3_open(&char(path.str), &db) if code != 0 { return &SQLError{ @@ -182,7 +182,7 @@ pub fn (db &DB) get_affected_rows_count() int { // q_int returns a single integer value, from the first column of the result of executing `query` pub fn (db &DB) q_int(query string) int { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) defer { C.sqlite3_finalize(stmt) } @@ -195,7 +195,7 @@ pub fn (db &DB) q_int(query string) int { // q_string returns a single string value, from the first column of the result of executing `query` pub fn (db &DB) q_string(query string) string { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) defer { C.sqlite3_finalize(stmt) } @@ -210,7 +210,7 @@ pub fn (db &DB) q_string(query string) string { // Result codes: https://www.sqlite.org/rescode.html [manualfree] pub fn (db &DB) exec(query string) ([]Row, int) { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) defer { C.sqlite3_finalize(stmt) } @@ -278,7 +278,7 @@ pub fn (db &DB) error_message(code int, query string) IError { // Use it, in case you don't expect any row results, but still want a result code. // e.g. for queries like these: `INSERT INTO ... VALUES (...)` pub fn (db &DB) exec_none(query string) int { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0) code := C.sqlite3_step(stmt) C.sqlite3_finalize(stmt) diff --git a/vlib/db/sqlite/stmt.v b/vlib/db/sqlite/stmt.v index 74ebc3be82..4e96fc0618 100644 --- a/vlib/db/sqlite/stmt.v +++ b/vlib/db/sqlite/stmt.v @@ -8,7 +8,7 @@ fn C.sqlite3_bind_text(&C.sqlite3_stmt, int, &char, int, voidptr) int // Only for V ORM fn (db &DB) init_stmt(query string) (&C.sqlite3_stmt, int) { // println('init_stmt("$query")') - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) err := C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0) return stmt, err } diff --git a/vlib/db/sqlite/vfs_lowlevel.v b/vlib/db/sqlite/vfs_lowlevel.v index db8abfe486..09c64dd19f 100644 --- a/vlib/db/sqlite/vfs_lowlevel.v +++ b/vlib/db/sqlite/vfs_lowlevel.v @@ -149,7 +149,7 @@ pub enum OpenModeFlag { // connect_full Opens connection to sqlite database. It gives more control than `open`. // Flags give control over readonly and create decisions. Specific VFS can be chosen. pub fn connect_full(path string, mode_flags []OpenModeFlag, vfs_name string) !DB { - db := &C.sqlite3(0) + db := &C.sqlite3(unsafe { nil }) mut flags := 0 diff --git a/vlib/dlmalloc/dlmalloc.v b/vlib/dlmalloc/dlmalloc.v index 3e7527d032..342cb0336c 100644 --- a/vlib/dlmalloc/dlmalloc.v +++ b/vlib/dlmalloc/dlmalloc.v @@ -1355,7 +1355,7 @@ fn (mut dl Dlmalloc) segment_holding(ptr voidptr) &Segment { } sp = sp.next } - return &Segment(0) + return &Segment(unsafe { nil }) } // realloc behaves as libc realloc, but operates within the given space diff --git a/vlib/net/address.v b/vlib/net/address.v index 99c52377ea..f5b34f3035 100644 --- a/vlib/net/address.v +++ b/vlib/net/address.v @@ -194,7 +194,7 @@ pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr { hints.ai_socktype = int(typ) hints.ai_flags = C.AI_PASSIVE - results := &C.addrinfo(0) + results := &C.addrinfo(unsafe { nil }) sport := '${port}' diff --git a/vlib/net/common.v b/vlib/net/common.v index 5bc9247556..14b8efc70a 100644 --- a/vlib/net/common.v +++ b/vlib/net/common.v @@ -70,7 +70,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool { // infinite timeout is signaled by passing null as the timeout to // select if timeout == net.infinite_timeout { - timeval_timeout = &C.timeval(0) + timeval_timeout = &C.timeval(unsafe { nil }) } match test { diff --git a/vlib/net/mbedtls/ssl_connection.v b/vlib/net/mbedtls/ssl_connection.v index 963422d612..f353216b31 100644 --- a/vlib/net/mbedtls/ssl_connection.v +++ b/vlib/net/mbedtls/ssl_connection.v @@ -379,7 +379,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool { // infinite timeout is signaled by passing null as the timeout to // select if timeout == net.infinite_timeout { - timeval_timeout = &C.timeval(0) + timeval_timeout = &C.timeval(unsafe { nil }) } match test { diff --git a/vlib/net/openssl/openssl_compiles_test.v b/vlib/net/openssl/openssl_compiles_test.v index aac82c34e7..17f2598d0c 100644 --- a/vlib/net/openssl/openssl_compiles_test.v +++ b/vlib/net/openssl/openssl_compiles_test.v @@ -5,7 +5,7 @@ struct Abc { } fn test_printing_struct_with_reference_field_of_type_ssl_ctx() { - a := Abc{&C.SSL_CTX(123)} + a := unsafe { Abc{&C.SSL_CTX(123)} } dump(a) sa := a.str() assert sa.contains('&C.SSL_CTX(0x7b)') diff --git a/vlib/net/openssl/ssl_connection.v b/vlib/net/openssl/ssl_connection.v index 7ca3c0f6bf..d82a198c11 100644 --- a/vlib/net/openssl/ssl_connection.v +++ b/vlib/net/openssl/ssl_connection.v @@ -436,7 +436,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool { // infinite timeout is signaled by passing null as the timeout to // select if timeout == net.infinite_timeout { - timeval_timeout = &C.timeval(0) + timeval_timeout = &C.timeval(unsafe { nil }) } match test { diff --git a/vlib/net/unix/common.v b/vlib/net/unix/common.v index ec9da8faf1..3ce379d145 100644 --- a/vlib/net/unix/common.v +++ b/vlib/net/unix/common.v @@ -42,7 +42,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool { // infinite timeout is signaled by passing null as the timeout to // select if timeout == unix.infinite_timeout { - timeval_timeout = &C.timeval(0) + timeval_timeout = &C.timeval(unsafe { nil }) } match test { diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index fe09e2b2ad..ed1f5e89f0 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -272,7 +272,7 @@ pub fn ls(path string) ![]string { if isnil(dir) { return error('ls() couldnt open dir "${path}"') } - mut ent := &C.dirent(0) + mut ent := &C.dirent(unsafe { nil }) // mut ent := &C.dirent{!} for { ent = C.readdir(dir) diff --git a/vlib/sqlite/sqlite.v b/vlib/sqlite/sqlite.v index 77e1ca5610..664957ef8d 100644 --- a/vlib/sqlite/sqlite.v +++ b/vlib/sqlite/sqlite.v @@ -126,7 +126,7 @@ fn C.sqlite3_changes(&C.sqlite3) int // connect Opens the connection with a database. pub fn connect(path string) !DB { - db := &C.sqlite3(0) + db := &C.sqlite3(unsafe { nil }) code := C.sqlite3_open(&char(path.str), &db) if code != 0 { return &SQLError{ @@ -181,7 +181,7 @@ pub fn (db &DB) get_affected_rows_count() int { // Returns a single cell with value int. pub fn (db &DB) q_int(query string) int { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) defer { C.sqlite3_finalize(stmt) } @@ -194,7 +194,7 @@ pub fn (db &DB) q_int(query string) int { // Returns a single cell with value string. pub fn (db &DB) q_string(query string) string { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) defer { C.sqlite3_finalize(stmt) } @@ -209,7 +209,7 @@ pub fn (db &DB) q_string(query string) string { // Result codes: https://www.sqlite.org/rescode.html [manualfree] pub fn (db &DB) exec(query string) ([]Row, int) { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) defer { C.sqlite3_finalize(stmt) } @@ -276,7 +276,7 @@ pub fn (db &DB) error_message(code int, query string) IError { // In case you don't expect any row results, but still want a result code. // e.g. INSERT INTO ... VALUES (...) pub fn (db &DB) exec_none(query string) int { - stmt := &C.sqlite3_stmt(0) + stmt := &C.sqlite3_stmt(unsafe { nil }) C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0) code := C.sqlite3_step(stmt) C.sqlite3_finalize(stmt) diff --git a/vlib/sqlite/vfs_lowlevel.v b/vlib/sqlite/vfs_lowlevel.v index 78d5814c82..d21c1e1297 100644 --- a/vlib/sqlite/vfs_lowlevel.v +++ b/vlib/sqlite/vfs_lowlevel.v @@ -149,7 +149,7 @@ pub enum OpenModeFlag { // connect_full Opens connection to sqlite database. It gives more control than `open`. // Flags give control over readonly and create decisions. Specific VFS can be chosen. pub fn connect_full(path string, mode_flags []OpenModeFlag, vfs_name string) !DB { - db := &C.sqlite3(0) + db := &C.sqlite3(unsafe { nil }) mut flags := 0 diff --git a/vlib/term/ui/input_nix.c.v b/vlib/term/ui/input_nix.c.v index f74b450aec..8e8e84e6df 100644 --- a/vlib/term/ui/input_nix.c.v +++ b/vlib/term/ui/input_nix.c.v @@ -11,7 +11,7 @@ mut: read_all_bytes bool = true } -const ctx_ptr = &Context(0) +const ctx_ptr = &Context(unsafe { nil }) // init initializes the terminal console with Config `cfg`. pub fn init(cfg Config) &Context { diff --git a/vlib/term/ui/input_windows.c.v b/vlib/term/ui/input_windows.c.v index 6972f2308f..d8ba7f408e 100644 --- a/vlib/term/ui/input_windows.c.v +++ b/vlib/term/ui/input_windows.c.v @@ -8,7 +8,7 @@ import time const buf_size = 64 -const ctx_ptr = &Context(0) +const ctx_ptr = &Context(unsafe { nil }) const stdin_at_startup = u32(0) diff --git a/vlib/term/ui/termios_nix.c.v b/vlib/term/ui/termios_nix.c.v index 75c2126995..1d88cff2d1 100644 --- a/vlib/term/ui/termios_nix.c.v +++ b/vlib/term/ui/termios_nix.c.v @@ -255,7 +255,7 @@ fn (mut ctx Context) parse_events() { if nr_iters > 100 { ctx.shift(1) } - mut event := &Event(0) + mut event := &Event(unsafe { nil }) if ctx.read_buf[0] == 0x1b { e, len := escape_sequence(ctx.read_buf.bytestr()) event = e @@ -420,7 +420,7 @@ fn escape_sequence(buf_ string) (&Event, int) { if buf.len > 2 && buf[1] == `<` { split := buf[2..].split(';') if split.len < 3 { - return &Event(0), 0 + return &Event(unsafe { nil }), 0 } typ, x, y := split[0].int(), split[1].int(), split[2].int() diff --git a/vlib/toml/tests/toml_bom_test.v b/vlib/toml/tests/toml_bom_test.v index e47f8e88cb..fba1dd706d 100644 --- a/vlib/toml/tests/toml_bom_test.v +++ b/vlib/toml/tests/toml_bom_test.v @@ -4,7 +4,7 @@ import toml.to import toml.ast const empty_toml_document = toml.Doc{ - ast: &ast.Root(0) + ast: &ast.Root(unsafe { nil }) } const ( diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 5d91a130e4..045d151e95 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -102,7 +102,7 @@ pub fn new_table() &Table { return t } -__global global_table = &Table(0) +__global global_table = &Table(unsafe { nil }) pub fn set_global_table(t &Table) { global_table = t diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index aac14ace1c..67e3316c5f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2836,6 +2836,30 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { if from_sym.kind == .alias { from_type = (from_sym.info as ast.Alias).parent_type.derive_add_muls(from_type) } + if mut node.expr is ast.IntegerLiteral { + if node.expr.val.int() == 0 && !c.pref.translated && !c.file.is_translated { + c.error('cannot null cast a struct pointer, use &${to_sym.name}(unsafe { nil })', + node.pos) + } else if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated { + c.error('cannot cast int to a struct pointer outside `unsafe`', node.pos) + } + } else if mut node.expr is ast.Ident { + match mut node.expr.obj { + ast.GlobalField, ast.ConstField, ast.Var { + if mut node.expr.obj.expr is ast.IntegerLiteral { + if node.expr.obj.expr.val.int() == 0 && !c.pref.translated + && !c.file.is_translated { + c.error('cannot null cast a struct pointer, use &${to_sym.name}(unsafe { nil })', + node.pos) + } else if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated { + c.error('cannot cast int to a struct pointer outside `unsafe`', + node.pos) + } + } + } + else {} + } + } if from_type == ast.voidptr_type_idx && !c.inside_unsafe { // TODO make this an error c.warn('cannot cast voidptr to a struct outside `unsafe`', node.pos) @@ -3611,9 +3635,10 @@ fn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type { } fn (mut c Checker) unsafe_expr(mut node ast.UnsafeExpr) ast.Type { + prev_unsafe := c.inside_unsafe c.inside_unsafe = true t := c.expr(node.expr) - c.inside_unsafe = false + c.inside_unsafe = prev_unsafe return t } diff --git a/vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.out b/vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.out new file mode 100644 index 0000000000..059072a44f --- /dev/null +++ b/vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.out @@ -0,0 +1,18 @@ +vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv:6:5: error: cannot cast int to a struct pointer outside `unsafe` + 4 | a := 1 + 5 | + 6 | _ = &Context(a) + | ~~~~~~~~~~~ + 7 | _ = &Context(b) + 8 | _ = &Context(1) +vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv:7:5: error: cannot cast int to a struct pointer outside `unsafe` + 5 | + 6 | _ = &Context(a) + 7 | _ = &Context(b) + | ~~~~~~~~~~~ + 8 | _ = &Context(1) +vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv:8:5: error: cannot cast int to a struct pointer outside `unsafe` + 6 | _ = &Context(a) + 7 | _ = &Context(b) + 8 | _ = &Context(1) + | ~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv b/vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv new file mode 100644 index 0000000000..3bbe0f58c6 --- /dev/null +++ b/vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv @@ -0,0 +1,8 @@ +struct Context {} + +const b = 1 +a := 1 + +_ = &Context(a) +_ = &Context(b) +_ = &Context(1) diff --git a/vlib/v/checker/tests/struct_ptr_cast_zero_err.out b/vlib/v/checker/tests/struct_ptr_cast_zero_err.out new file mode 100644 index 0000000000..ee9fda1898 --- /dev/null +++ b/vlib/v/checker/tests/struct_ptr_cast_zero_err.out @@ -0,0 +1,18 @@ +vlib/v/checker/tests/struct_ptr_cast_zero_err.vv:6:5: error: cannot null cast a struct pointer, use &Context(unsafe { nil }) + 4 | b := 0 + 5 | + 6 | _ = &Context(0) + | ~~~~~~~~~~~ + 7 | _ = &Context(a) + 8 | _ = &Context(b) +vlib/v/checker/tests/struct_ptr_cast_zero_err.vv:7:5: error: cannot null cast a struct pointer, use &Context(unsafe { nil }) + 5 | + 6 | _ = &Context(0) + 7 | _ = &Context(a) + | ~~~~~~~~~~~ + 8 | _ = &Context(b) +vlib/v/checker/tests/struct_ptr_cast_zero_err.vv:8:5: error: cannot null cast a struct pointer, use &Context(unsafe { nil }) + 6 | _ = &Context(0) + 7 | _ = &Context(a) + 8 | _ = &Context(b) + | ~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/struct_ptr_cast_zero_err.vv b/vlib/v/checker/tests/struct_ptr_cast_zero_err.vv new file mode 100644 index 0000000000..4597d54a4d --- /dev/null +++ b/vlib/v/checker/tests/struct_ptr_cast_zero_err.vv @@ -0,0 +1,8 @@ +struct Context {} + +const a = 0 +b := 0 + +_ = &Context(0) +_ = &Context(a) +_ = &Context(b) diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 2b57264435..491a84bd93 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -428,7 +428,7 @@ pub fn (mut g JsGen) enter_namespace(name string) { } pub fn (mut g JsGen) escape_namespace() { - g.ns = &Namespace(0) + g.ns = &Namespace(unsafe { nil }) g.inside_builtin = false } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 4435da4251..1a5de77e3e 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -179,7 +179,7 @@ pub fn (mut p Parser) free_scanner() { unsafe { if p.scanner != 0 { p.scanner.free() - p.scanner = &scanner.Scanner(0) + p.scanner = &scanner.Scanner(nil) } } } diff --git a/vlib/v/pkgconfig/main.v b/vlib/v/pkgconfig/main.v index 5c3f5a253d..2e2faad695 100644 --- a/vlib/v/pkgconfig/main.v +++ b/vlib/v/pkgconfig/main.v @@ -78,7 +78,7 @@ pub fn (mut m Main) run() !string { } // m.opt = options opt := m.opt - mut pc := &PkgConfig(0) + mut pc := &PkgConfig(unsafe { nil }) mut res := m.res for arg in opt.args { mut pcdep := load(arg, options) or { diff --git a/vlib/v/tests/cast_to_alias_test.v b/vlib/v/tests/cast_to_alias_test.v index 9592b8f667..80556a43dd 100644 --- a/vlib/v/tests/cast_to_alias_test.v +++ b/vlib/v/tests/cast_to_alias_test.v @@ -41,11 +41,11 @@ struct Foo { type Alias = Foo fn test_cast_to_alias_of_ref_struct() { - foo := &Foo(0) + foo := &Foo(unsafe { nil }) println(typeof(foo).name) assert typeof(foo).name == '&Foo' - bar := &Alias(0) + bar := &Alias(unsafe { nil }) println(typeof(bar).name) assert typeof(bar).name == '&Alias' } diff --git a/vlib/v/token/keywords_matcher_trie.v b/vlib/v/token/keywords_matcher_trie.v index 517a823944..0cc74c7d27 100644 --- a/vlib/v/token/keywords_matcher_trie.v +++ b/vlib/v/token/keywords_matcher_trie.v @@ -67,7 +67,7 @@ pub fn new_keywords_matcher_trie[T](kw_map map[string]T) KeywordsMatcherTrie { nodes: []&TrieNode{cap: 20} } for _ in 0 .. 20 { - km.nodes << &TrieNode(0) + km.nodes << &TrieNode(unsafe { nil }) } for k, v in kw_map { km.add_word(k, int(v)) diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index 2b5bbcdc7e..89e9acd000 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -297,7 +297,7 @@ mut: [unsafe] pub fn cached_read_source_file(path string) !string { - mut static cache := &SourceCache(0) + mut static cache := &SourceCache(unsafe { nil }) if cache == unsafe { nil } { cache = &SourceCache{} } @@ -308,7 +308,7 @@ pub fn cached_read_source_file(path string) !string { if path.len == 0 { unsafe { cache.sources.free() } unsafe { free(cache) } - cache = &SourceCache(0) + cache = &SourceCache(unsafe { nil }) return error('memory source file cache cleared') } diff --git a/vlib/vweb/tests/middleware_test.v b/vlib/vweb/tests/middleware_test.v index ff468fd3e0..78c2a6d753 100644 --- a/vlib/vweb/tests/middleware_test.v +++ b/vlib/vweb/tests/middleware_test.v @@ -267,7 +267,7 @@ struct SimpleTcpClientConfig { } fn simple_tcp_client(config SimpleTcpClientConfig) !string { - mut client := &net.TcpConn(0) + mut client := &net.TcpConn(unsafe { nil }) mut tries := 0 for tries < config.retries { tries++ @@ -308,7 +308,7 @@ ${config.content}' } fn simple_tcp_client_post_json(config SimpleTcpClientConfig) !string { - mut client := &net.TcpConn(0) + mut client := &net.TcpConn(unsafe { nil }) mut tries := 0 for tries < config.retries { tries++ diff --git a/vlib/vweb/tests/vweb_test.v b/vlib/vweb/tests/vweb_test.v index 0ee17190eb..183478b6a8 100644 --- a/vlib/vweb/tests/vweb_test.v +++ b/vlib/vweb/tests/vweb_test.v @@ -266,7 +266,7 @@ struct SimpleTcpClientConfig { } fn simple_tcp_client(config SimpleTcpClientConfig) !string { - mut client := &net.TcpConn(0) + mut client := &net.TcpConn(unsafe { nil }) mut tries := 0 for tries < config.retries { tries++