jackc / jackc/pgx

TOC/TOU bug on transaction rollback

Open
#2,551 4 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Go
Stars
14.3k
Forks
1.1k
Avg merge
6d 9h
Merged PRs (30d)
11

Description

**Describe the bug**

I have observed flaky behavior in a test that causes a transaction to be rolled back by canceling the context. I think it is caused by a toctou issue here:

https://github.com/jackc/pgx/blob/c00cd65970e579cb722fc65fe2508e4cd1e4cb8f/tx.go#L210-L215

**To Reproduce**

It is a hard to reproduce issue without lots of setup, this is what is happening roughly:

```go
func TestRollbackOnContextCanceled(t *testing.T) {
dsn := dockertest.RunTestPostgreSQL(t) // or simply load from the env

db, err := sql.Open("pgx/v5", dsn)
require.NoError(t, err)
t.Cleanup(func() { _ = db.Close() })
require.EventuallyWithT(t, func(collect *assert.CollectT) {
assert.NoError(collect, db.PingContext(t.Context()))
}, 10*time.Second, 100*time.Millisecond)

ctx, cancel := context.WithCancel(t.Context())
t.Cleanup(cancel)

tx, err := db.BeginTx(ctx, nil)
require.NoError(t, err)

_, err = tx.ExecContext(ctx, "SELECT 1")
require.NoError(t, err)

cancel()
time.Sleep(1 * time.Nanosecond) // give the database/sql auto-rollback some time to kick in

// this races now with the database/sql auto-rollback on context cancellation
// https://github.com/golang/go/blob/07840ceeed4afd10324a552e8c87a8ee363aa24a/src/database/sql/sql.go#L2211-L2226
// depending on the outcome, we either get sql.ErrTxDone or "conn closed"
require.NoError(t, tx.Rollback())
}
```

**Expected behavior**

The close bool flag should be managed atomically, similar to how it is done in the `database/sql` package: https://github.com/golang/go/blob/07840ceeed4afd10324a552e8c87a8ee363aa24a/src/database/sql/sql.go#L2331

**Actual behavior**

Flaky behavior.

**Version**
- Go: `$ go version` -> go version go1.26.2 darwin/arm64
- PostgreSQL: `$ psql --no-psqlrc --tuples-only -c 'select version()'` -> PostgreSQL 16.13 (Debian 16.13-1.pgdg13+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
- pgx: `$ grep 'github.com/jackc/pgx/v[0-9]' go.mod` -> v5.9.2

**Additional context**

...

Contributor guide

Open the contributing guide

Research direction

Start with tx.go lines 210-215 and compare the close-flag handling with the referenced database/sql implementation around sql.go line 2331. Use the provided TestRollbackOnContextCanceled scenario to investigate the race; done means rollback behavior is consistent and the regression is covered by a test.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, postgresql
Domain
database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.