Skip to content

sync: deadlock when calling any sync.Map method inside Map.Range callback #5528

Description

@fxamacker

What happened?

Deadlock occurs when a sync.Map's Range callback calls any method (e.g. Load, Store, Delete) on that same map.

Go's sync.Map states that Range callback doesn't block when calling other methods on m: "Range does not block other methods on the receiver; even f itself may call any method on m."

Minimal reproducer

package main

import "sync"

func main() {
        var m sync.Map
        m.Store(1, 1)
        m.Range(func(k, v any) bool {
                m.Delete(k) // hangs forever here
                return true
        })
}

go run main.go exits immediately, as expected.

tinygo run main.go hangs indefinitely and never returns.

Root cause

src/sync/map.go is a plain map guarded by a single non-reentrant task.PMutex, and every method holds that lock for its entire duration.

Range likewise holds the lock across the user callback, so any sync.Map method called from inside the callback deadlocks.

Reproduction environment

  • TinyGo 0.41.1, linux/amd64 (go1.26.4, LLVM 20.1.1)
  • TinyGo 0.42.0 dev, commit 801bd48, linux/amd64 (go1.26.4, LLVM 20.1.8)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions