redis / go-redis

Redis Go client
https://redis.uptrace.dev
BSD 2-Clause "Simplified" License
19.6k stars 2.31k forks source link

fatal error: concurrent map iteration and map write #3021

Open jekhy opened 3 weeks ago

jekhy commented 3 weeks ago
fatal error: concurrent map iteration and map write

goroutine 42 [running]:
runtime.throw({0xe66a8d?, 0xc000600000?})
    /usr/local/go/src/runtime/panic.go:992 +0x71 fp=0xc00e496ec0 sp=0xc00e496e90 pc=0x438731
runtime.mapiternext(0xc1bcb72518?)
    /usr/local/go/src/runtime/map.go:871 +0x4eb fp=0xc00e496f30 sp=0xc00e496ec0 pc=0x41002b
reflect.mapiternext(0x49ad8f?)
    /usr/local/go/src/runtime/map.go:1378 +0x19 fp=0xc00e496f48 sp=0xc00e496f30 pc=0x464ff9
reflect.(*MapIter).Next(0xc1bcb72500?)
    /usr/local/go/src/reflect/value.go:1789 +0x7e fp=0xc00e496f78 sp=0xc00e496f48 pc=0x49afbe
internal/fmtsort.Sort({0xd3a3a0?, 0xc00023a9c8?, 0xc00023a9c0?})
    /usr/local/go/src/internal/fmtsort/sort.go:63 +0x159 fp=0xc00e497038 sp=0xc00e496f78 pc=0x4a9dd9
fmt.(*pp).printValue(0xc031a2e750, {0xd3a3a0?, 0xc00023a9c8?, 0xc0113c5860?}, 0x76, 0x2)
    /usr/local/go/src/fmt/print.go:769 +0x445 fp=0xc00e497220 sp=0xc00e497038 pc=0x4e7885
fmt.(*pp).printValue(0xc031a2e750, {0xe07c40?, 0xc00023a9a0?, 0x1b9?}, 0x76, 0x1)
    /usr/local/go/src/fmt/print.go:806 +0x124e fp=0xc00e497408 sp=0xc00e497220 pc=0x4e868e
fmt.(*pp).printValue(0xc031a2e750, {0xe0ed00?, 0xc000412b00?, 0xde61b0?}, 0x76, 0x0)
    /usr/local/go/src/fmt/print.go:876 +0xce5 fp=0xc00e4975f0 sp=0xc00e497408 pc=0x4e8125
fmt.(*pp).badVerb(0xc031a2e750, 0x412b00?)
    /usr/local/go/src/fmt/print.go:343 +0x457 fp=0xc00e497698 sp=0xc00e4975f0 pc=0x4e4bd7
fmt.(*pp).fmtPointer(0xc031a2e750, {0xe0ed00?, 0xc000412b00?, 0x0?}, 0x73)
    /usr/local/go/src/fmt/print.go:532 +0x418 fp=0xc00e497738 sp=0xc00e497698 pc=0x4e5e98
fmt.(*pp).printValue(0xc031a2e750, {0xe0ed00?, 0xc000412b00?, 0x0?}, 0x73, 0x2)
    /usr/local/go/src/fmt/print.go:882 +0xef7 fp=0xc00e497920 sp=0xc00e497738 pc=0x4e8337
fmt.(*pp).printValue(0xc031a2e750, {0xde6160?, 0xc000412b00?, 0xc000471b80?}, 0x73, 0x1)
    /usr/local/go/src/fmt/print.go:806 +0x124e fp=0xc00e497b08 sp=0xc00e497920 pc=0x4e868e
fmt.(*pp).printValue(0xc031a2e750, {0xd59b40?, 0xc000412b00?, 0xc005e6b220?}, 0x73, 0x0)
    /usr/local/go/src/fmt/print.go:876 +0xce5 fp=0xc00e497cf0 sp=0xc00e497b08 pc=0x4e8125
fmt.(*pp).printArg(0xc031a2e750, {0xd59b40?, 0xc000412b00}, 0x73)
    /usr/local/go/src/fmt/print.go:712 +0x74c fp=0xc00e497d90 sp=0xc00e497cf0 pc=0x4e73ac
fmt.(*pp).doPrintf(0xc031a2e750, {0xe72c9a, 0x35}, {0xc0a1e6cc00?, 0x2, 0x2})
    /usr/local/go/src/fmt/print.go:1026 +0x288 fp=0xc00e497e88 sp=0xc00e497d90 pc=0x4e9ba8
fmt.Sprintf({0xe72c9a, 0x35}, {0xc0a1e6cc00, 0x2, 0x2})
    /usr/local/go/src/fmt/print.go:219 +0x59 fp=0xc00e497ee0 sp=0xc00e497e88 pc=0x4e4019
github.com/go-redis/redis/v8/internal.(*logger).Printf(0x1570180, {0xc000471f68?, 0xc0000cc008?}, {0xe72c9a?, 0x1?}, {0xc0a1e6cc00?, 0xc0005847b0?, 0xc000584780?})
    /root/go/pkg/mod/github.com/go-redis/redis/v8@v8.11.5/internal/log.go:19 +0x37 fp=0xc00e497f18 sp=0xc00e497ee0 pc=0x64cad7
github.com/go-redis/redis/v8.(*channel).initMsgChan.func1()
    /root/go/pkg/mod/github.com/go-redis/redis/v8@v8.11.5/pubsub.go:605 +0x31a fp=0xc00e497fe0 sp=0xc00e497f18 pc=0x69563a
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:1571 +0x1 fp=0xc00e497fe8 sp=0xc00e497fe0 pc=0x46b601
created by github.com/go-redis/redis/v8.(*channel).initMsgChan
    /root/go/pkg/mod/github.com/go-redis/redis/v8@v8.11.5/pubsub.go:565 +0xca

The error is reported as above.

I found that in many places in the code, the struct object containing the map field will be directly passed in as a log parameter, which will trigger the iteration of the map when logging, but the map is not locked, so there is a hidden danger of triggering a panic.

internal.Logger.Printf(
    ctx, "redis: %s channel is full for %s (message is dropped)",
    c, c.chanSendTimeout)