Go version

go1.24.0

Output of go env in your module/workspace:

AR='ar'
CC='clang'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='clang++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/Users/aryank.upadhyay@zomato.com/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/aryank.upadhyay@zomato.com/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/xm/5fwwh80x6vz1xgft05lyp3800000gn/T/go-build1603238070=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/Users/aryank.upadhyay@zomato.com/go/src/github.com/Zomato/search-service/go.mod'
GOMODCACHE='/Users/aryank.upadhyay@zomato.com/go/pkg/mod'
GONOPROXY='github.com/Zomato/*'
GONOSUMDB='github.com/Zomato/*'
GOOS='darwin'
GOPATH='/Users/aryank.upadhyay@zomato.com/go'
GOPRIVATE='github.com/Zomato/*'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/aryank.upadhyay@zomato.com/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.24.0.darwin-arm64'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/aryank.upadhyay@zomato.com/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/aryank.upadhyay@zomato.com/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.24.0.darwin-arm64/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

We are iterating over the docs through function GetFieldToDocsMap. Share below the piece of code

type Document struct {
    Doc map[string]interface{}
    mux sync.RWMutex `json:"-" msgpack:"-" snappy:"-"`
}

func GetFieldToDocsMap(fieldName string, docs []*Document) map[int]*Document {
    resToDocMap := make(map[int]*index.Document)
    for i := range docs {
        id, ok := Int(docs[i].Get(fieldName))
        if !ok {
            continue
        }
        resToDocMap[id] = docs[i]
    }
    return resToDocMap
}

func (d *Document) Set(k string, v interface{}) {
    if d == nil {
        return
    }
    d.mux.Lock()
    defer d.mux.Unlock()
    d.Doc[k] = v
}


func (d *Document) Get(k string) (v interface{}) {
    if d == nil {
        return
    }
    d.mux.RLock()
    defer d.mux.RUnlock()
    v = d.Doc[k]
    return v
}

We are using the using the docs multiple times in same request with proper synchronisation. also the function GetFieldToDocsMap is used in various go-routines.

docsMap := GetFieldToDocsMap("ID", Response.ModifiedResult.Results.Docs)

type IndexResult struct {
    Status              int
    Results             *Collection 
}

type Collection struct {
    Docs      []*Document
    Start     int
    NumFound  int
}

type Response struct {
    ModifiedResult                  *IndexResult
    AlphaResult                        *IndexResult
        StausValue                           bool
        ....
}

What did you see happen?

unexpected fault address 0x37303037313132
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0x37303037313132 pc=0x1b3b0]

goroutine 97106282 gp=0x415e9761c0 m=2 mp=0x4000108808 [running]:
runtime.throw({0x44abf46?, 0xeeb624?})
    /usr/local/go/src/runtime/panic.go:1096 +0x38 fp=0x4250f16880 sp=0x4250f16850 pc=0x9e818
runtime.sigpanic()
    /usr/local/go/src/runtime/signal_unix.go:939 +0x224 fp=0x4250f168e0 sp=0x4250f16880 pc=0xa15f4
internal/runtime/maps.(*Map).Used(...)
    /usr/local/go/src/internal/runtime/maps/map.go:389
runtime.mapaccess1_faststr(0x39d7ac0?, 0x422cd05e00?, {0x44b70cf?, 0xeef930?})
    /usr/local/go/src/internal/runtime/maps/runtime_faststr_swiss.go:110 +0x20 fp=0x4250f16970 sp=0x4250f168f0 pc=0x1b3b0
github.com/Zomato/search-service/internal/index.(*Document).Get(0x39e3b20?, {0x44b70cf?, 0x149c6b5?})
    /go/src/github.com/Zomato/search-service/internal/index/response.go:279

goroutine 2 gp=0x4000002700 m=nil [force gc (idle), 513 minutes]:
runtime.gopark(...)
    /usr/local/go/src/runtime/proc.go:435
runtime.goparkunlock(0x0?, 0x0?, 0x0?, 0x0?)
    /usr/local/go/src/runtime/proc.go:441 +0xd0 fp=0x4000104fa0 sp=0x4000104f80 pc=0x5e4c0
runtime.forcegchelper()
    /usr/local/go/src/runtime/proc.go:348 +0xac fp=0x4000104fd0 sp=0x4000104fa0 pc=0x5e31c
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x4000104fd0 sp=0x4000104fd0 pc=0xa81f4
created by runtime.init.7 in goroutine 1
    /usr/local/go/src/runtime/proc.go:336 +0x24

goroutine 3 gp=0x4000002c40 m=nil [GC sweep wait]:
runtime.gopark(...)
    /usr/local/go/src/runtime/proc.go:435
runtime.goparkunlock(0x85efb01?, 0x0?, 0x44?, 0x0?)
    /usr/local/go/src/runtime/proc.go:441 +0xd0 fp=0x4000105730 sp=0x4000105710 pc=0x5e4c0
runtime.bgsweep(0x4000122000)
    /usr/local/go/src/runtime/mgcsweep.go:316 +0xf0 fp=0x40001057b0 sp=0x4000105730 pc=0x41640
runtime.gcenable.gowrap1()
    /usr/local/go/src/runtime/mgc.go:204 +0x28 fp=0x40001057d0 sp=0x40001057b0 pc=0x33db8
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x40001057d0 sp=0x40001057d0 pc=0xa81f4
created by runtime.gcenable in goroutine 1
    /usr/local/go/src/runtime/mgc.go:204 +0x6c

goroutine 4 gp=0x4000002e00 m=nil [GC scavenge wait]:
runtime.gopark(...)
    /usr/local/go/src/runtime/proc.go:435
runtime.goparkunlock(0x4e3984?, 0x1f?, 0xff?, 0x0?)
    /usr/local/go/src/runtime/proc.go:441 +0xd0 fp=0x4000105f60 sp=0x4000105f40 pc=0x5e4c0
runtime.(*scavengerState).park(0x85dee20)
    /usr/local/go/src/runtime/mgcscavenge.go:425 +0x50 fp=0x4000105f90 sp=0x4000105f60 pc=0x3ed40
runtime.bgscavenge(0x4000122000)
    /usr/local/go/src/runtime/mgcscavenge.go:658 +0xac fp=0x4000105fb0 sp=0x4000105f90 pc=0x3f2cc
runtime.gcenable.gowrap2()
    /usr/local/go/src/runtime/mgc.go:205 +0x28 fp=0x4000105fd0 sp=0x4000105fb0 pc=0x33d58
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x4000105fd0 sp=0x4000105fd0 pc=0xa81f4
created by runtime.gcenable in goroutine 1
    /usr/local/go/src/runtime/mgc.go:205 +0xac

goroutine 17 gp=0x4000238000 m=nil [finalizer wait]:
runtime.gopark(0x0?, 0x424dc15b18?, 0xc0?, 0x51?, 0x1000000010?)
    /usr/local/go/src/runtime/proc.go:435 +0xc8 fp=0x4008233d90 sp=0x4008233d70 pc=0x9e938
runtime.runfinq()
    /usr/local/go/src/runtime/mfinal.go:196 +0x108 fp=0x4008233fd0 sp=0x4008233d90 pc=0x32e08
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x4008233fd0 sp=0x4008233fd0 pc=0xa81f4
created by runtime.createfing in goroutine 1
    /usr/local/go/src/runtime/mfinal.go:166 +0x80

goroutine 18 gp=0x40004508c0 m=nil [GC worker (idle)]:
runtime.gopark(0x1c1215e42557?, 0x3?, 0x8f?, 0xa3?, 0x0?)
    /usr/local/go/src/runtime/proc.go:435 +0xc8 fp=0x40087caf10 sp=0x40087caef0 pc=0x9e938
runtime.gcBgMarkWorker(0x40002020e0)
    /usr/local/go/src/runtime/mgc.go:1423 +0xdc fp=0x40087cafb0 sp=0x40087caf10 pc=0x3642c
runtime.gcBgMarkStartWorkers.gowrap1()
    /usr/local/go/src/runtime/mgc.go:1339 +0x28 fp=0x40087cafd0 sp=0x40087cafb0 pc=0x36318
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x40087cafd0 sp=0x40087cafd0 pc=0xa81f4
created by runtime.gcBgMarkStartWorkers in goroutine 1
    /usr/local/go/src/runtime/mgc.go:1339 +0x140

goroutine 33 gp=0x4000182380 m=nil [GC worker (idle)]:
runtime.gopark(0x1c110bb368cb?, 0x3?, 0xa9?, 0xdf?, 0x0?)
    /usr/local/go/src/runtime/proc.go:435 +0xc8 fp=0x4004080f10 sp=0x4004080ef0 pc=0x9e938
runtime.gcBgMarkWorker(0x40002020e0)
    /usr/local/go/src/runtime/mgc.go:1423 +0xdc fp=0x4004080fb0 sp=0x4004080f10 pc=0x3642c
runtime.gcBgMarkStartWorkers.gowrap1()
    /usr/local/go/src/runtime/mgc.go:1339 +0x28 fp=0x4004080fd0 sp=0x4004080fb0 pc=0x36318
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x4004080fd0 sp=0x4004080fd0 pc=0xa81f4
created by runtime.gcBgMarkStartWorkers in goroutine 1
    /usr/local/go/src/runtime/mgc.go:1339 +0x140

goroutine 5 gp=0x40000036c0 m=nil [GC worker (idle), 262 minutes]:
runtime.gopark(0xdbf6f0a523c?, 0x3?, 0x92?, 0x6b?, 0x0?)
    /usr/local/go/src/runtime/proc.go:435 +0xc8 fp=0x40de956f10 sp=0x40de956ef0 pc=0x9e938
runtime.gcBgMarkWorker(0x40002020e0)
    /usr/local/go/src/runtime/mgc.go:1423 +0xdc fp=0x40de956fb0 sp=0x40de956f10 pc=0x3642c
runtime.gcBgMarkStartWorkers.gowrap1()
    /usr/local/go/src/runtime/mgc.go:1339 +0x28 fp=0x40de956fd0 sp=0x40de956fb0 pc=0x36318
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x40de956fd0 sp=0x40de956fd0 pc=0xa81f4
created by runtime.gcBgMarkStartWorkers in goroutine 1
    /usr/local/go/src/runtime/mgc.go:1339 +0x140

goroutine 6 gp=0x4000003880 m=nil [GC worker (idle)]:
runtime.gopark(0x1c1215e52396?, 0x3?, 0xbb?, 0xdf?, 0x0?)
    /usr/local/go/src/runtime/proc.go:435 +0xc8 fp=0x4006feef10 sp=0x4006feeef0 pc=0x9e938
runtime.gcBgMarkWorker(0x40002020e0)
    /usr/local/go/src/runtime/mgc.go:1423 +0xdc fp=0x4006feefb0 sp=0x4006feef10 pc=0x3642c
runtime.gcBgMarkStartWorkers.gowrap1()
    /usr/local/go/src/runtime/mgc.go:1339 +0x28 fp=0x4006feefd0 sp=0x4006feefb0 pc=0x36318
runtime.goexit({})
    /usr/local/go/src/runtime/asm_arm64.s:1223 +0x4 fp=0x4006feefd0 sp=0x4006feefd0 pc=0xa81f4
created by runtime.gcBgMarkStartWorkers in goroutine 1
    /usr/local/go/src/runtime/mgc.go:1339 +0x140

What did you expect to see?

Expectation: go build never crashes

Currently it seems like the fatal error is caused due to corrupt address. But in our code flow we are never directly updating the Document value. We use the Set method { shared the implementation above }

Here is piece of code which produces almost same stack trace:

func main() {
    // A valid map
    x := map[string]int{"foo": 42}

    // Create a pointer to the map
    y := &x

    // Now override the address of y with a pointer to a string
    s := "7007112" // corrupt memory: these bytes will become the map header
    ptrToY := (*unsafe.Pointer)(unsafe.Pointer(&y))
    stringPtr := *(*unsafe.Pointer)(unsafe.Pointer(&s))
    *ptrToY = stringPtr

    // Force a runtime access to the corrupted map — triggers SIGSEGV
    fmt.Println((*y)["someKey"])
}

Comment From: adonovan

Are you able to reproduce the problem? If so, have you tried using the -race flag to eliminate the possibility of a data race? (Though your locking does look sound.)

@prattmic

Comment From: prattmic

The fault address 0x37303037313132 looks an awful lot like ASCII data, so a race condition or other unsafe misuse seems likely to me. Note that string is struct{ data unsafe.Pointer; len int }, so if Document were overwritten by a string value then the map pointer becomes the pointer to the string contents.