pgx icon indicating copy to clipboard operation
pgx copied to clipboard

Map.memoizedEncodePlans concurrent map writes (v5.7.2)

Open Se7ge opened this issue 9 months ago • 3 comments

Describe the bug When using a simple protocol and concurrent queries, a panic occurs with the error concurrent map writes in the memoizedEncodePlans function in the pgtype.Map module.

fatal error: concurrent map writes
...
github.com/jackc/pgx/v5/pgtype.(*Map).planEncodeDepth(0xc01173e5b0, 0x0, 0x0, {0x3aeda0, 0x648cfc0}, 0x0)
        /-S/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go:1254 +0x206 fp=0xc00cd08b08 sp=0xc00cd08a58 pc=0x3ef3bc6
github.com/jackc/pgx/v5/pgtype.(*Map).PlanEncode(...)
        /-S/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go:1234
github.com/jackc/pgx/v5/pgtype.(*Map).Encode(0xc01173e5b0, 0x0, 0x0, {0x3aeda0, 0x648cfc0}, {0x6488500, 0x0, 0x0})
        /-S/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go:2001 +0x12d fp=0xc00cd08b58 sp=0xc00cd08b08 pc=0x3ef99ed
github.com/jackc/pgx/v5.convertSimpleArgument(0x4c8380?, {0x3aeda0?, 0x648cfc0?})
        /-S/vendor/github.com/jackc/pgx/v5/values.go:17 +0x34 fp=0xc00cd08ba0 sp=0xc00cd08b58 pc=0x3fe8e14
github.com/jackc/pgx/v5.(*Conn).sanitizeForSimpleQuery(0xc014d0e900, {0xc021f80340, 0x185}, {0xc01aa19190, 0x1, 0xc01aa19190?})
        /-S/vendor/github.com/jackc/pgx/v5/conn.go:1244 +0x166 fp=0xc00cd08bf8 sp=0xc00cd08ba0 pc=0x3fdfba6
github.com/jackc/pgx/v5.(*Conn).Query(0xc014d0e900, {0x121c170?, 0xc044094230?}, {0xc021f80340, 0x185}, {0xc01aa19180, 0x2, 0x2})
        /-S/vendor/github.com/jackc/pgx/v5/conn.go:838 +0xbab fp=0xc00cd08de0 sp=0xc00cd08bf8 pc=0x3fdc06b
github.com/jackc/pgx/v5/stdlib.(*Conn).QueryContext(0xc01bb55e40, {0x121c170, 0xc044094230}, {0xc021f80340, 0x185}, {0xc03d1b9f80, 0x1, 0x5f32600?})
        /-S/vendor/github.com/jackc/pgx/v5/stdlib/sql.go:493 +0x32d fp=0xc00cd08ed0 sp=0xc00cd08de0 pc=0x40223ed
...

Expected behavior

No concurrent map writes panic should occur.

Actual behavior

A panic with the concurrent map writes error occurs when executing concurrent queries, indicating an attempt to write to the map simultaneously.

Version

Go: 1.22.5
pgx: v5.7.2

Additional context

Part of the core dump:

(dlv) bt
 0  0x0000000002fd1ca1 in runtime.raise
    at /-S/contrib/go/_std_1.22/src/runtime/sys_linux_amd64.s:154
 1  0x0000000002fb1805 in runtime.dieFromSignal
    at /-S/contrib/go/_std_1.22/src/runtime/signal_unix.go:923
 2  0x0000000002fb1f06 in runtime.sigfwdgo
    at /-S/contrib/go/_std_1.22/src/runtime/signal_unix.go:1128
 3  0x0000000002fb0425 in runtime.sigtrampgo
    at /-S/contrib/go/_std_1.22/src/runtime/signal_unix.go:432
 4  0x0000000002fd1ca1 in runtime.raise
    at /-S/contrib/go/_std_1.22/src/runtime/sys_linux_amd64.s:153
 5  0x0000000002fb1805 in runtime.dieFromSignal
    at /-S/contrib/go/_std_1.22/src/runtime/signal_unix.go:923
 6  0x0000000002f99c3a in runtime.crash
    at /-S/contrib/go/_std_1.22/src/runtime/signal_unix.go:1005
 7  0x0000000002f99c3a in runtime.fatalthrow.func1
    at /-S/contrib/go/_std_1.22/src/runtime/panic.go:1203
 8  0x0000000002fce48a in runtime.systemstack
    at /-S/contrib/go/_std_1.22/src/runtime/asm_amd64.s:509
 9  0x0000000002fce428 in runtime.systemstack_switch
    at /-S/contrib/go/_std_1.22/src/runtime/asm_amd64.s:474
10  0x0000000002f99b85 in runtime.fatalthrow
    at /-S/contrib/go/_std_1.22/src/runtime/panic.go:1192
11  0x0000000002f9981c in runtime.fatal
    at /-S/contrib/go/_std_1.22/src/runtime/panic.go:1042
12  0x0000000002f6f54e in runtime.mapassign
    at /-S/contrib/go/_std_1.22/src/runtime/map.go:596
13  0x0000000003ef3bc6 in github.com/jackc/pgx/v5/pgtype.(*Map).planEncodeDepth
    at /-S/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go:1254
14  0x0000000003ef99ed in github.com/jackc/pgx/v5/pgtype.(*Map).PlanEncode
    at /-S/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go:1234
15  0x0000000003ef99ed in github.com/jackc/pgx/v5/pgtype.(*Map).Encode
    at /-S/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go:2001
16  0x0000000003fe8e14 in github.com/jackc/pgx/v5.convertSimpleArgument
    at /-S/vendor/github.com/jackc/pgx/v5/values.go:17
17  0x0000000003fdfba6 in github.com/jackc/pgx/v5.(*Conn).sanitizeForSimpleQuery
    at /-S/vendor/github.com/jackc/pgx/v5/conn.go:1244
18  0x0000000003fdc06b in github.com/jackc/pgx/v5.(*Conn).Query
    at /-S/vendor/github.com/jackc/pgx/v5/conn.go:838
19  0x00000000040223ed in github.com/jackc/pgx/v5/stdlib.(*Conn).QueryContext
    at /-S/vendor/github.com/jackc/pgx/v5/stdlib/sql.go:493

...

oid = 0
format = 0

Possible solution

Protect map modification https://github.com/jackc/pgx/blob/04bcc0219dc3acf67f27e68decd6dffe97334779/pgtype/pgtype.go#L1235 with mutex.

Se7ge avatar Mar 31 '25 12:03 Se7ge

When using a simple protocol and concurrent queries,

pgx.Conn and pgtype.Map are not concurrency safe. You probably want to use pgxpool.

jackc avatar Mar 31 '25 12:03 jackc

You probably want to use pgxpool

In the project, we are sticking to the stdlib database/sql DB and using its pool, while using pgx as a driver. What could you suggest in our case?

Se7ge avatar Mar 31 '25 13:03 Se7ge

The database/sql pool should be fine as well. But the underlying point remains, pgx.Conn is not concurrency safe and access to it must be mediated by something else. If it's getting a concurrency failure that means something outside of the pgx.Conn is failing.

You might want to run with the race detector. It can give more information about where the invalid concurrent access is occurring.

jackc avatar Mar 31 '25 13:03 jackc