Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

calling map.clear() fails to change the receiver map, in such a way that it has the exact same observable behaviour as doing m = {} for some maps #22148

Closed
spytheman opened this issue Sep 1, 2024 · 4 comments
Labels
Bug This tag is applied to issues which reports bugs. Modules: builtin Bugs and problems, concerning the builtin types in V - array, maps, strings, runes.

Comments

@spytheman
Copy link
Member

spytheman commented Sep 1, 2024

V doctor:

V full version: V 0.4.7 62c69e8.673ac0a
OS: linux, Ubuntu 20.04.6 LTS
Processor: 2 cpus, 64bit, little endian, Intel(R) Core(TM) i3-3225 CPU @ 3.30GHz

getwd: /space/v/oo
vexe: /space/v/oo/v
vexe mtime: 2024-09-01 09:48:38

vroot: OK, value: /space/v/oo
VMODULES: OK, value: /home/delian/.vmodules
VTMP: OK, value: /tmp/v_1000

Git version: git version 2.46.0
Git vroot status: weekly.2024.35-7-g33f74cf1
.git/config present: true

CC version: cc (Ubuntu 10.5.0-1ubuntu1~20.04) 10.5.0
thirdparty/tcc status: thirdparty-linux-amd64 0134e9b9

What did you do?
./v -g -o vdbg cmd/v && ./vdbg x_test.v

const t = [928, 897, 165, 563, 52, 619, 525, 414, 555, 254, 788, 118, 534, 0, 181]

fn test_multiple_iterations_of_calling_clear_should_be_always_equivalent_to_assigning_a_new_map() {
	println('array t len: ${t.len}, t: ${t}')
	mut clr := map[int]int{}
	for i in 0 .. 0xFFFF {
		mut new := map[int]int{}
		clr.clear()
		for e in t {
			new[e] = e
			clr[e] = e
			assert new == clr, 'e: ${e} i: ${i}'
		}
		assert new == clr, 'mismatch found for iteration: ${i}'
	}
}

What did you expect to see?

a passing test

What did you see instead?

array t len: 15, t: [928, 897, 165, 563, 52, 619, 525, 414, 555, 254, 788, 118, 534, 0, 181]
x_test.v:12: fn test_multiple_iterations_of_calling_clear_should_be_always_equivalent_to_assigning_a_new_map
  > assert new == clr, 'e: $e i: $i'
    Left value:
      {928: 928, 897: 897, 165: 165, 563: 563, 52: 52, 619: 619, 525: 525, 414: 414, 555: 555, 254: 254, 788: 788, 118: 118, 534: 534, 0: 0}
    Right value:
      {928: 928, 897: 897, 165: 165, 563: 563, 52: 52, 619: 619, 525: 525, 414: 414, 555: 555, 254: 254, 788: 788, 118: 118, 534: 534}
        Message: e: 0 i: 1

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

@spytheman spytheman added Bug This tag is applied to issues which reports bugs. Modules: builtin Bugs and problems, concerning the builtin types in V - array, maps, strings, runes. labels Sep 1, 2024
@spytheman spytheman changed the title calling map.clear() fails to have the exact same observable behaviour to m = {} for some maps calling map.clear() fails to change the receiver map, in such a way that it has the exact same observable behaviour as doing m = {} for some maps Sep 1, 2024
@spytheman
Copy link
Member Author

Note: this specific combination of keys, was discovered, after running the randomized test described in #22146 for ~1 hour.

@spytheman
Copy link
Member Author

More keys that can lead to the same or similar problem, can be found by running this program:

import rand

fn get_random_numbers() []int {
	mut res := []int{}
	n := rand.u32n(50) or { 5 }
	for _ in 0 .. n {
		x := rand.intn(100) or { 0 }
		// if x == 0 { continue } // filtering out the 0 key, makes failures much less likely (sorted keys *with 0*, are also much less likely to fail)
		res << x
	}
	// return res.sorted() // sorting reduces the chances of a `new.len != clr.len` *a lot*
	return res
}

fn random_keys_with_map_clear(iteration int) {
	t := get_random_numbers()
	mut clr := map[int]int{}
	for i in 0 .. 256 {
		mut new := map[int]int{}
		clr.clear()
		for e in t {
			new[e] = e
			clr[e] = e
			if new.len != clr.len {
				println('# new.len == ${new.len:3} != clr.len == ${clr.len:3} \n    i: ${i:4} e: ${e:4} | t.len: ${t.len:3}, t: ${t}')
				return
			}
		}
		if new != clr {
			println('# new != clr \n    i: ${i:4} | t.len: ${t.len:3}, t: ${t}')
			return
		}
	}
}

fn main() {
	for i := 0; i < 999_999_999; i++ {
		if 0 == i % 10000 {
			println('##### iteration: ${i}')
		}
		random_keys_with_map_clear(i)
	}
}

(preferably with v -prod -cc clang crun stress_map_clear.v)

@spytheman
Copy link
Member Author

For example:

#0 22:08:01 ^ master /v/oo>v -prod -cc clang-18 crun stress_map_clear.v 
##### iteration: 0
# new.len ==  14 != clr.len ==  13 
    i:    1 e:    0 | t.len:  18, t: [75, 33, 21, 21, 87, 22, 37, 41, 62, 98, 8, 24, 14, 80, 0, 73, 18, 43]
# new.len ==  17 != clr.len ==  16 
    i:    1 e:    0 | t.len:  28, t: [43, 27, 68, 41, 79, 53, 97, 24, 44, 95, 8, 24, 50, 18, 55, 32, 69, 0, 47, 11, 77, 2, 93, 84, 97, 83, 0, 76]
# new.len ==  16 != clr.len ==  15 
    i:    1 e:    0 | t.len:  27, t: [51, 9, 19, 99, 63, 8, 72, 17, 85, 44, 77, 87, 49, 3, 53, 0, 98, 56, 51, 76, 86, 33, 31, 98, 35, 80, 75]
# new.len ==  19 != clr.len ==  18 
    i:    1 e:    0 | t.len:  22, t: [42, 72, 11, 72, 94, 52, 9, 20, 22, 6, 55, 11, 4, 33, 2, 89, 34, 29, 10, 44, 0, 99]
# new.len ==  14 != clr.len ==  13 
    i:    3 e:    0 | t.len:  20, t: [61, 68, 97, 24, 28, 28, 39, 40, 62, 94, 77, 71, 91, 21, 0, 55, 82, 22, 53, 70]
# new.len ==  17 != clr.len ==  16 
    i:    1 e:    0 | t.len:  25, t: [22, 63, 75, 55, 66, 87, 47, 62, 68, 44, 6, 21, 76, 27, 11, 97, 0, 45, 58, 94, 80, 22, 4, 49, 75]
# new.len ==  18 != clr.len ==  17 
    i:    1 e:    0 | t.len:  26, t: [91, 47, 74, 7, 54, 86, 65, 26, 5, 92, 18, 93, 29, 58, 58, 47, 63, 35, 89, 0, 16, 58, 75, 33, 19, 40]
# new.len ==  23 != clr.len ==  22 
    i:    1 e:    0 | t.len:  30, t: [64, 87, 87, 36, 75, 20, 87, 18, 98, 95, 33, 63, 57, 86, 49, 77, 47, 57, 94, 91, 70, 95, 50, 40, 50, 17, 23, 0, 46, 74]
##### iteration: 10000
# new.len ==  23 != clr.len ==  22 
    i:    3 e:    0 | t.len:  32, t: [3, 14, 32, 79, 86, 7, 61, 87, 3, 25, 66, 44, 94, 7, 82, 24, 20, 26, 69, 32, 87, 58, 21, 56, 10, 87, 21, 58, 40, 10, 0, 29]
# new.len ==  15 != clr.len ==  14 
    i:    1 e:    0 | t.len:  24, t: [79, 90, 50, 20, 86, 14, 89, 52, 11, 39, 82, 55, 67, 39, 67, 36, 0, 95, 63, 53, 58, 78, 43, 24]
# new.len ==  15 != clr.len ==  14 
    i:    1 e:    0 | t.len:  20, t: [66, 95, 6, 31, 61, 5, 39, 67, 57, 24, 27, 96, 22, 95, 57, 88, 0, 39, 48, 31]
# new.len ==  19 != clr.len ==  18 
    i:    1 e:    0 | t.len:  25, t: [19, 54, 59, 47, 45, 60, 53, 48, 50, 17, 9, 69, 23, 94, 66, 18, 93, 81, 0, 67, 69, 39, 20, 41, 37]
# new.len ==  16 != clr.len ==  15 
    i:    1 e:    0 | t.len:  25, t: [58, 82, 20, 70, 4, 58, 93, 90, 33, 9, 41, 72, 43, 22, 67, 46, 0, 2, 32, 30, 87, 7, 88, 1, 58]
# new.len ==  21 != clr.len ==  20 
    i:    1 e:    0 | t.len:  26, t: [23, 96, 63, 80, 51, 19, 66, 65, 28, 1, 5, 49, 21, 93, 77, 49, 29, 84, 41, 68, 80, 32, 0, 97, 76, 91]
# new.len ==  18 != clr.len ==  17 
    i:    1 e:    0 | t.len:  19, t: [70, 74, 27, 39, 89, 71, 17, 1, 45, 62, 44, 54, 73, 44, 88, 69, 81, 11, 0]
# new.len ==  19 != clr.len ==  18 
    i:    1 e:    0 | t.len:  26, t: [52, 18, 42, 90, 42, 32, 52, 25, 14, 79, 77, 76, 80, 93, 34, 71, 4, 91, 69, 70, 0, 95, 50, 84, 73, 37]
# new.len ==  16 != clr.len ==  15 
    i:    1 e:    0 | t.len:  24, t: [37, 51, 53, 32, 18, 9, 8, 89, 26, 8, 54, 90, 16, 90, 39, 43, 59, 0, 4, 11, 2, 83, 84, 87]
# new.len ==  23 != clr.len ==  22 
    i:    1 e:    0 | t.len:  27, t: [21, 73, 4, 80, 11, 82, 24, 32, 67, 36, 49, 14, 28, 6, 33, 52, 17, 6, 33, 80, 94, 87, 27, 81, 8, 6, 0]
# new.len ==  17 != clr.len ==  16 
    i:    1 e:    0 | t.len:  24, t: [49, 24, 82, 48, 8, 66, 94, 45, 52, 23, 32, 56, 4, 53, 26, 83, 26, 0, 82, 31, 98, 94, 22, 20]
# new.len ==  19 != clr.len ==  18 
    i:    1 e:    0 | t.len:  23, t: [81, 11, 97, 65, 89, 74, 98, 22, 29, 64, 34, 50, 47, 14, 12, 7, 87, 47, 66, 0, 61, 97, 94]

@spytheman
Copy link
Member Author

This is also an interesting one, since the maps should be the same, but == considers them different:

# new != clr
    i:    2 | t.len:  23, t: [23, 21, 71, 63, 9, 13, 64, 61, 78, 79, 16, 64, 84, 89, 72, 67, 62, 18, 46, 89, 54, 95, 68]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug This tag is applied to issues which reports bugs. Modules: builtin Bugs and problems, concerning the builtin types in V - array, maps, strings, runes.
Projects
None yet
Development

No branches or pull requests

1 participant