From 50c5042047be3af36e7bb478435093ea45e8f1f0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 7 Dec 2015 14:22:08 -0500 Subject: [PATCH] runtime: best-effort detection of concurrent misuse of maps If reports like #13062 are really concurrent misuse of maps, we can detect that, at least some of the time, with a cheap check. There is an extra pair of memory writes for writing to a map, but to the same cache line as h.count, which is often being modified anyway, and there is an extra memory read for reading from a map, but to the same cache line as h.count, which is always being read anyway. So the check should be basically invisible and may help reduce the number of "mysterious runtime crash due to map misuse" reports. Change-Id: I0e71b0d92eaa3b7bef48bf41b0f5ab790092487e Reviewed-on: https://go-review.googlesource.com/17501 Reviewed-by: Keith Randall Reviewed-by: Brad Fitzpatrick Reviewed-by: Austin Clements --- src/runtime/hashmap.go | 37 ++++++++++++++++++++++++++++++++++--- src/runtime/hashmap_fast.go | 18 ++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 056396c518..892a79a914 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -95,6 +95,7 @@ const ( // flags iterator = 1 // there may be an iterator using buckets oldIterator = 2 // there may be an iterator using oldbuckets + hashWriting = 4 // a goroutine is writing to the map // sentinel bucket ID for iterator checks noCheck = 1<<(8*sys.PtrSize) - 1 @@ -284,6 +285,9 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil || h.count == 0 { return atomic.Loadp(unsafe.Pointer(&zeroptr)) } + if h.flags&hashWriting != 0 { + throw("concurrent map read and map write") + } alg := t.key.alg hash := alg.hash(key, uintptr(h.hash0)) m := uintptr(1)<