Skip to content

Map protected by mutex caused panic: concurrent map writes #20060

@VojtechVitek

Description

@VojtechVitek

I've got a simple package to protect map from concurrent read/writes via sync.Mutex. But from time to time I get panic concurrent map writes.

Can you guys see any issue with the below code? What am I doing wrong? Or is this a Go bug?

What did you do?

package stringmap

import "sync"

// concurrentStringMap is a concurrent storage for strings (emails, links etc.)
// that automatically removes duplicates. Very helpful for verifying output
// of Newsletter recipients or URL links in Newsletter HTML/Text.
type concurrentStringMap struct {
	sync.Mutex
	strings map[string]struct{}
}

func NewConcurrentStringMap() concurrentStringMap {
	return concurrentStringMap{
		strings: map[string]struct{}{},
	}
}

func (u concurrentStringMap) Add(str string) bool {
	u.Lock()
	defer u.Unlock()
	if _, ok := u.strings[str]; ok {
		return false
	}
	u.strings[str] = struct{}{} // panic happens here
	return true
}

func (u concurrentStringMap) Slice() []string {
	u.Lock()
	defer u.Unlock()
	slice := make([]string, 0, len(u.strings))
	for str, _ := range u.strings {
		slice = append(slice, str)
	}
	return slice
}

What did you expect to see?

No panic?

What did you see instead?

fatal error: concurrent map writes

goroutine 1194 [running]:
runtime.throw(0x1fe22bf, 0x15)
	/usr/local/go/src/runtime/panic.go:596 +0x95 fp=0xc420ca8dc8 sp=0xc420ca8da8
runtime.mapassign(0x1e03b40, 0xc420bbb890, 0xc420ca8ea0, 0x1b)
	/usr/local/go/src/runtime/hashmap.go:499 +0x667 fp=0xc420ca8e68 sp=0xc420ca8dc8
github.com/pressly/api/lib/stringmap.concurrentStringMap.Add(0x0, 0xc420bbb890, 0xc420ec7560, 0x1b, 0x0)
	***/stringmap/stringmap.go:25 +0x127 fp=0xc420ca8ec0 sp=0xc420ca8e68

Does this issue reproduce with the latest release (go1.8.1)?

System details

go version go1.8 darwin/amd64
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/vojtechvitek/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/hr/5zb8r0yx4sv4_1dc0rlccflm0000gn/T/go-build257984097=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
GOROOT/bin/go version: go version go1.8 darwin/amd64
GOROOT/bin/go tool compile -V: compile version go1.8 X:framepointer
uname -v: Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64
ProductName:	Mac OS X
ProductVersion:	10.12.3
BuildVersion:	16D32
lldb --version: lldb-370.0.40
  Swift-3.1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions