From 04e79e7b2a96bed2592d7939258ff455be82db16 Mon Sep 17 00:00:00 2001 From: CreeperFace <165158232+dy-tea@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:33:43 +0100 Subject: [PATCH 1/2] checker: prevent usage of imported module name prefix as identifier names, to avoid cgen collisions (#25280) --- vlib/v/checker/assign.v | 1 + vlib/v/checker/checker.v | 35 ++++++++++++++----- vlib/v/checker/fn.v | 1 + .../tests/clash_ident_module_name_prefix.out | 28 +++++++++++++++ .../tests/clash_ident_module_name_prefix.vv | 23 ++++++++++++ 5 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 vlib/v/checker/tests/clash_ident_module_name_prefix.out create mode 100644 vlib/v/checker/tests/clash_ident_module_name_prefix.vv diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index e9fc1495ab..af0b4b2633 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -444,6 +444,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if c.check_import_sym_conflict(left.name) { c.error('duplicate of an import symbol `${left.name}`', left.pos) } + c.check_module_name_conflict(left.name, left.pos) } if node.op == .assign && left_type.has_flag(.option) && right is ast.UnsafeExpr && right.expr.is_nil() { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 34b2cb8fc2..79b6a2cdd9 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -137,14 +137,15 @@ mut: inside_assign bool // doing_line_info int // a quick single file run when called with v -line-info (contains line nr to inspect) // doing_line_path string // same, but stores the path being parsed - is_index_assign bool - comptime_call_pos int // needed for correctly checking use before decl for templates - goto_labels map[string]ast.GotoLabel // to check for unused goto labels - enum_data_type ast.Type - field_data_type ast.Type - variant_data_type ast.Type - fn_return_type ast.Type - orm_table_fields map[string][]ast.StructField // known table structs + is_index_assign bool + comptime_call_pos int // needed for correctly checking use before decl for templates + goto_labels map[string]ast.GotoLabel // to check for unused goto labels + enum_data_type ast.Type + field_data_type ast.Type + variant_data_type ast.Type + fn_return_type ast.Type + orm_table_fields map[string][]ast.StructField // known table structs + short_module_names []string // to check for function names colliding with module functions v_current_commit_hash string // same as old C.V_CURRENT_COMMIT_HASH assign_stmt_attr string // for `x := [1,2,3] @[freed]` @@ -331,6 +332,14 @@ pub fn (mut c Checker) change_current_file(file &ast.File) { c.vmod_file_content = '' c.mod = file.mod.name c.is_generated = file.is_generated + c.short_module_names = ['builtin'] + for import_sym in c.file.imports { + c.short_module_names << if import_sym.alias == '' { + import_sym.mod.all_after_last('.') + } else { + import_sym.alias + } + } } pub fn (mut c Checker) check_files(ast_files []&ast.File) { @@ -5790,6 +5799,16 @@ fn (c &Checker) check_import_sym_conflict(ident string) bool { return false } +fn (mut c Checker) check_module_name_conflict(ident string, pos token.Pos) { + if ident.contains('__') { + prefix := ident.all_before('__') + if prefix in c.short_module_names { + c.error('identifier cannot use prefix `${prefix}__` of imported module `${prefix}`', + pos) + } + } +} + // update_unresolved_fixed_sizes updates the unresolved type symbols for array fixed return type and alias type. pub fn (mut c Checker) update_unresolved_fixed_sizes() { for mut stmt in c.unresolved_fixed_sizes { diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 12b2d8a357..0c2b338fa4 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -104,6 +104,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { if !node.is_method && node.mod == 'main' && node.short_name in c.table.builtin_pub_fns { c.error('cannot redefine builtin public function `${node.short_name}`', node.pos) } + c.check_module_name_conflict(node.short_name, node.pos) } if node.name == 'main.main' { c.main_fn_decl_node = *node diff --git a/vlib/v/checker/tests/clash_ident_module_name_prefix.out b/vlib/v/checker/tests/clash_ident_module_name_prefix.out new file mode 100644 index 0000000000..4a756ca522 --- /dev/null +++ b/vlib/v/checker/tests/clash_ident_module_name_prefix.out @@ -0,0 +1,28 @@ +vlib/v/checker/tests/clash_ident_module_name_prefix.vv:7:1: error: identifier cannot use prefix `builtin__` of imported module `builtin` + 5 | // os is not imported so the os__ prefix should not produce an error + 6 | + 7 | fn builtin__string_str() { + | ~~~~~~~~~~~~~~~~~~~~~~~~ + 8 | } + 9 | +vlib/v/checker/tests/clash_ident_module_name_prefix.vv:10:1: error: identifier cannot use prefix `time__` of imported module `time` + 8 | } + 9 | + 10 | fn time__utc() { + | ~~~~~~~~~~~~~~ + 11 | } + 12 | +vlib/v/checker/tests/clash_ident_module_name_prefix.vv:17:2: error: identifier cannot use prefix `builtin__` of imported module `builtin` + 15 | + 16 | fn main() { + 17 | builtin__string_str := 'Hello V!'.str() + | ~~~~~~~~~~~~~~~~~~~ + 18 | time__now := time.now() + 19 | os__log := 'Hello V!' +vlib/v/checker/tests/clash_ident_module_name_prefix.vv:18:2: error: identifier cannot use prefix `time__` of imported module `time` + 16 | fn main() { + 17 | builtin__string_str := 'Hello V!'.str() + 18 | time__now := time.now() + | ~~~~~~~~~ + 19 | os__log := 'Hello V!' + 20 | println(builtin__string_str) \ No newline at end of file diff --git a/vlib/v/checker/tests/clash_ident_module_name_prefix.vv b/vlib/v/checker/tests/clash_ident_module_name_prefix.vv new file mode 100644 index 0000000000..738dfde11f --- /dev/null +++ b/vlib/v/checker/tests/clash_ident_module_name_prefix.vv @@ -0,0 +1,23 @@ +import time + +// builtin__ prefix should always produce an error +// time is imported so the time__ prefix should always produce an error +// os is not imported so the os__ prefix should not produce an error + +fn builtin__string_str() { +} + +fn time__utc() { +} + +fn os__getwd() { +} + +fn main() { + builtin__string_str := 'Hello V!'.str() + time__now := time.now() + os__log := 'Hello V!' + println(builtin__string_str) + println(time__now) + println(os__log) +} From 56f20d1ff8ce8c1f68bb3cee1bb241e7e2f45bb3 Mon Sep 17 00:00:00 2001 From: blackshirt Date: Fri, 12 Sep 2025 03:36:11 +0700 Subject: [PATCH 2/2] x.crypto.ascon: small cleanups and optimization (#25284) --- vlib/x/crypto/ascon/ascon.v | 19 +++++++++++++------ vlib/x/crypto/ascon/digest.v | 33 ++++++++++++++++++++++----------- vlib/x/crypto/ascon/util.v | 16 +++++++++++++--- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/vlib/x/crypto/ascon/ascon.v b/vlib/x/crypto/ascon/ascon.v index 8bb1b1977a..1ebd5bab84 100644 --- a/vlib/x/crypto/ascon/ascon.v +++ b/vlib/x/crypto/ascon/ascon.v @@ -41,6 +41,9 @@ fn ascon_pnr(mut s State, nr int) { if nr < 1 || nr > 16 { panic('Invalid round number') } + // Allocate temporary vars to reduce allocation within loop + mut x0 := u64(0) + mut y0 := u64(0) // Ascon permutation routine for i := max_nr_perm - nr; i < max_nr_perm; i++ { // 3.2 Constant-Addition Layer step @@ -56,18 +59,22 @@ fn ascon_pnr(mut s State, nr int) { s.e0 ^= s.e4 s.e4 ^= s.e3 s.e2 ^= s.e1 - + // Set temp vars to values + x0 = s.e0 + y0 = s.e4 ^ (~s.e0 & s.e1) + /* t0 := s.e4 ^ (~s.e0 & s.e1) t1 := s.e0 ^ (~s.e1 & s.e2) t2 := s.e1 ^ (~s.e2 & s.e3) t3 := s.e2 ^ (~s.e3 & s.e4) t4 := s.e3 ^ (~s.e4 & s.e0) + */ - s.e0 = t1 - s.e1 = t2 - s.e2 = t3 - s.e3 = t4 - s.e4 = t0 + s.e0 = s.e0 ^ (~s.e1 & s.e2) // t1 + s.e1 = s.e1 ^ (~s.e2 & s.e3) // t2 + s.e2 = s.e2 ^ (~s.e3 & s.e4) // t3 + s.e3 = s.e3 ^ (~s.e4 & x0) // t4, change s.e0 to x0 + s.e4 = y0 s.e1 ^= s.e0 s.e0 ^= s.e4 diff --git a/vlib/x/crypto/ascon/digest.v b/vlib/x/crypto/ascon/digest.v index 89a7dac7e1..07ee9ad303 100644 --- a/vlib/x/crypto/ascon/digest.v +++ b/vlib/x/crypto/ascon/digest.v @@ -135,20 +135,32 @@ fn (mut d Digest) squeeze(mut dst []u8) int { } @[direct_array_access; inline] -fn ascon_generic_hash(mut s State, msg_ []u8, size int) []u8 { +fn ascon_generic_hash(mut s State, msg []u8, size int) []u8 { // Assumed state was correctly initialized // Absorbing the message - mut msg := msg_.clone() - for msg.len >= block_size { - s.e0 ^= binary.little_endian_u64(msg[0..block_size]) - unsafe { - msg = msg[block_size..] + mut pos := 0 + // Check if msg has non-null length, if yes, absorb it. + // Otherwise, just pad it + if _likely_(msg.len > 0) { + mut msg_len := msg.len + for msg_len >= block_size { + s.e0 ^= binary.little_endian_u64(msg[pos..pos + block_size]) + pos += block_size + msg_len -= block_size + ascon_pnr(mut s, ascon_prnd_12) } - ascon_pnr(mut s, ascon_prnd_12) + // Absorb the last partial message block + last_block := unsafe { msg[pos..] } + s.e0 ^= u64(0x01) << (8 * last_block.len) // pad(last_block.len) + if last_block.len > 0 { + s.e0 ^= load_bytes(last_block, last_block.len) + } + } else { + // Otherwise, just pad it + s.e0 ^= u64(0x01) } - // Absorb the last partial message block - s.e0 ^= load_bytes(msg, msg.len) - s.e0 ^= pad(msg.len) + // reset pos + pos = 0 // Squeezing phase // @@ -156,7 +168,6 @@ fn ascon_generic_hash(mut s State, msg_ []u8, size int) []u8 { // permutation 𝐴𝑠𝑐𝑜𝑛-𝑝[12] to the state: ascon_pnr(mut s, ascon_prnd_12) mut out := []u8{len: size} - mut pos := 0 mut clen := out.len for clen >= block_size { binary.little_endian_put_u64(mut out[pos..pos + 8], s.e0) diff --git a/vlib/x/crypto/ascon/util.v b/vlib/x/crypto/ascon/util.v index 345683ea66..97e70d5e98 100644 --- a/vlib/x/crypto/ascon/util.v +++ b/vlib/x/crypto/ascon/util.v @@ -83,13 +83,23 @@ fn set_byte(b u8, i int) u64 { fn load_bytes(bytes []u8, n int) u64 { mut x := u64(0) for i := 0; i < n; i++ { - x |= set_byte(bytes[i], i) + // This is the same way to store bytes in little-endian way + // x |= u64(bytes[0]) << 8*0 // LSB at lowest index + // x |= u64(bytes[1]) << 8*1 + // x |= u64(bytes[2]) << 8*2 + // x |= u64(bytes[3]) << 8*3 + // ...etc + // x |= u64(bytes[7]) << 8*7 // MSB at highest index + x |= u64(bytes[i]) << (8 * i) } - return u64le(x) + // No need to cast with u64le, its alread le + return x } +@[direct_array_access] fn store_bytes(mut out []u8, x u64, n int) { for i := 0; i < n; i++ { - out[i] = get_byte(x, i) + // use underlying get_byte directly + out[i] = u8(x >> (8 * i)) } }