From 1f8fa4941f632575468498bfac48fc1cbbf1a54f Mon Sep 17 00:00:00 2001 From: Youlin Feng Date: Tue, 5 Nov 2024 17:21:57 +0800 Subject: [PATCH] runtime: fix iterator returns map entries after clear (pre-swissmap) Fixes #70189 Fixes #59411 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest-noswissmap Change-Id: I4ef7ecd7e996330189309cb2a658cf34bf9e1119 Reviewed-on: https://go-review.googlesource.com/c/go/+/625275 Reviewed-by: Keith Randall Reviewed-by: Keith Randall Auto-Submit: Keith Randall Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- .../internal/reflectdata/map_noswiss.go | 14 ++++--- src/reflect/map_noswiss.go | 1 + src/runtime/map_noswiss.go | 28 ++++---------- src/runtime/map_noswiss_test.go | 4 +- test/fixedbugs/issue70189.go | 38 +++++++++++++++++++ 5 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 test/fixedbugs/issue70189.go diff --git a/src/cmd/compile/internal/reflectdata/map_noswiss.go b/src/cmd/compile/internal/reflectdata/map_noswiss.go index 07d0bb9049..a6fab4cbac 100644 --- a/src/cmd/compile/internal/reflectdata/map_noswiss.go +++ b/src/cmd/compile/internal/reflectdata/map_noswiss.go @@ -155,6 +155,7 @@ func OldMapType() *types.Type { // buckets unsafe.Pointer // oldbuckets unsafe.Pointer // nevacuate uintptr + // clearSeq uint64 // extra unsafe.Pointer // *mapextra // } // must match runtime/map.go:hmap. @@ -167,6 +168,7 @@ func OldMapType() *types.Type { makefield("buckets", types.Types[types.TUNSAFEPTR]), // Used in walk.go for OMAKEMAP. makefield("oldbuckets", types.Types[types.TUNSAFEPTR]), makefield("nevacuate", types.Types[types.TUINTPTR]), + makefield("clearSeq", types.Types[types.TUINT64]), makefield("extra", types.Types[types.TUNSAFEPTR]), } @@ -178,9 +180,9 @@ func OldMapType() *types.Type { hmap.SetUnderlying(types.NewStruct(fields)) types.CalcSize(hmap) - // The size of hmap should be 48 bytes on 64 bit - // and 28 bytes on 32 bit platforms. - if size := int64(8 + 5*types.PtrSize); hmap.Size() != size { + // The size of hmap should be 56 bytes on 64 bit + // and 36 bytes on 32 bit platforms. + if size := int64(2*8 + 5*types.PtrSize); hmap.Size() != size { base.Fatalf("hmap size not correct: got %d, want %d", hmap.Size(), size) } @@ -216,6 +218,7 @@ func OldMapIterType() *types.Type { // i uint8 // bucket uintptr // checkBucket uintptr + // clearSeq uint64 // } // must match runtime/map.go:hiter. fields := []*types.Field{ @@ -234,6 +237,7 @@ func OldMapIterType() *types.Type { makefield("i", types.Types[types.TUINT8]), makefield("bucket", types.Types[types.TUINTPTR]), makefield("checkBucket", types.Types[types.TUINTPTR]), + makefield("clearSeq", types.Types[types.TUINT64]), } // build iterator struct holding the above fields @@ -244,8 +248,8 @@ func OldMapIterType() *types.Type { hiter.SetUnderlying(types.NewStruct(fields)) types.CalcSize(hiter) - if hiter.Size() != int64(12*types.PtrSize) { - base.Fatalf("hash_iter size not correct %d %d", hiter.Size(), 12*types.PtrSize) + if hiter.Size() != int64(8+12*types.PtrSize) { + base.Fatalf("hash_iter size not correct %d %d", hiter.Size(), 8+12*types.PtrSize) } oldHiterType = hiter diff --git a/src/reflect/map_noswiss.go b/src/reflect/map_noswiss.go index 81d7b6222a..99609829f0 100644 --- a/src/reflect/map_noswiss.go +++ b/src/reflect/map_noswiss.go @@ -256,6 +256,7 @@ type hiter struct { i uint8 bucket uintptr checkBucket uintptr + clearSeq uint64 } func (h *hiter) initialized() bool { diff --git a/src/runtime/map_noswiss.go b/src/runtime/map_noswiss.go index d7b8a5fe11..327f0c81e8 100644 --- a/src/runtime/map_noswiss.go +++ b/src/runtime/map_noswiss.go @@ -123,6 +123,7 @@ type hmap struct { buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated) + clearSeq uint64 extra *mapextra // optional fields } @@ -176,6 +177,7 @@ type hiter struct { i uint8 bucket uintptr checkBucket uintptr + clearSeq uint64 } // bucketShift returns 1<