pingcap / pingcap/tidb

data-race: ProcessInfo.ToRow() reads StmtCtx without RefCountOfStmtCtx protection

Open
#68,542 2 comments 0 reactions 0 assignees View on GitHub
severity/moderate sig/sql-infra type/bug
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Bug Report

### Description

`ProcessInfo.ToRow()` reads `pi.StmtCtx` fields (such as `MemTracker`, `AffectedRows`) without using the `RefCountOfStmtCtx` protection mechanism. Meanwhile, the session goroutine can concurrently reset the same `StatementContext` via `InitStatementContext()` → `StatementContext.Reset()` or `InitMemTracker()`.

This causes a data race detected by the Go race detector.

### Race Pattern

- **WRITE** (session goroutine): `executeStmtImpl()` → `ResetContextOfStmt()` → `InitStatementContext()` → `StatementContext.Reset()` or `InitMemTracker()` — writes to a `StatementContext` object.
- **READ** (background goroutine): `servermemorylimit.Handle.Run()` → `killSessIfNeeded()` → `recordOne()` → `info.ToRow()` — reads `pi.StmtCtx.MemTracker`, `pi.StmtCtx.AffectedRows()` from the same `StatementContext`.

### Root Cause

The existing `RefCountOfStmtCtx` mechanism (`TryIncrease()/Decrease()`) is designed to protect concurrent access to `StmtCtx`. `GenLogFields()` in `pkg/util/util.go` correctly uses this protection, but `ToRow()` does not.

### Reproduction

Seen in CI for `TestGlobalMemoryControlForPrepareAnalyze` with race detector enabled. The test spawns a background goroutine running `servermemorylimit.Handle.Run()` while executing ANALYZE statements.

### Fix

Add `RefCountOfStmtCtx` protection in `ProcessInfo.ToRow()`, following the same pattern used by `GenLogFields()`. If `TryIncrease` fails (the StmtCtx is being frozen/reset), skip the StmtCtx-dependent fields.

### Example Race Log

```
WARNING: DATA RACE
Write at 0x00c006d14d88 by goroutine 62:
github.com/pingcap/tidb/pkg/sessionctx/stmtctx.(*StatementContext).InitMemTracker()
pkg/sessionctx/stmtctx/stmtctx.go:976 +0x1031
github.com/pingcap/tidb/pkg/executor.ResetContextOfStmt()
pkg/executor/select.go:1014 +0x1002

Previous read at 0x00c006d14d88 by goroutine 11384:
github.com/pingcap/tidb/pkg/session/sessmgr.(*ProcessInfo).ToRow()
pkg/session/sessmgr/processinfo.go:146 +0x108
github.com/pingcap/tidb/pkg/util/servermemorylimit.recordOne()
pkg/util/servermemorylimit/servermemorylimit.go:224 +0xec
github.com/pingcap/tidb/pkg/util/servermemorylimit.killSessIfNeeded()
pkg/util/servermemorylimit/servermemorylimit.go:184 +0x15e4
```

### Affected Files

- `pkg/session/sessmgr/processinfo.go` — `ToRow()` method
- `pkg/util/servermemorylimit/servermemorylimit.go` — caller `recordOne()`
- `pkg/executor/infoschema_reader.go` — another caller of `ToRow()` without protection

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.