]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: fix maps.Clone bug when cloning a map mid-grow
authorKeith Randall <khr@golang.org>
Wed, 23 Aug 2023 22:19:15 +0000 (15:19 -0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Fri, 25 Aug 2023 16:10:03 +0000 (16:10 +0000)
Fixes #62203

Change-Id: I0459d3f481b0cd20102f6d9fd3ea84335a7739a8
Reviewed-on: https://go-review.googlesource.com/c/go/+/522317
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/runtime/map.go
test/fixedbugs/issue62203.go [new file with mode: 0644]

index 5d4e470b9e0b70539659b02099833dfbb2b4b568..e6d651f688380ea2647a3fca38730174f387f96d 100644 (file)
@@ -1553,7 +1553,7 @@ func mapclone2(t *maptype, src *hmap) *hmap {
                }
 
                if oldB >= dst.B { // main bucket bits in dst is less than oldB bits in src
-                       dstBmap := (*bmap)(add(dst.buckets, uintptr(i)&bucketMask(dst.B)))
+                       dstBmap := (*bmap)(add(dst.buckets, (uintptr(i)&bucketMask(dst.B))*uintptr(t.BucketSize)))
                        for dstBmap.overflow(t) != nil {
                                dstBmap = dstBmap.overflow(t)
                        }
diff --git a/test/fixedbugs/issue62203.go b/test/fixedbugs/issue62203.go
new file mode 100644 (file)
index 0000000..8c93d78
--- /dev/null
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+       "maps"
+)
+
+func main() {
+       m := map[string]struct{}{}
+
+       // Fill m up to the max for 4 buckets = 48 entries.
+       for i := 0; i < 48; i++ {
+               m[fmt.Sprintf("%d", i)] = struct{}{}
+       }
+
+       // Add a 49th entry, to start a grow to 8 buckets.
+       m["foo"] = struct{}{}
+
+       // Remove that 49th entry. m is still growing to 8 buckets,
+       // but a clone of m will only have 4 buckets because it
+       // only needs to fit 48 entries.
+       delete(m, "foo")
+
+       // Clone an 8-bucket map to a 4-bucket map.
+       _ = maps.Clone(m)
+}