Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os: Race condition in (* os.File).readdir() #71496

Closed
mitmitmitm opened this issue Jan 31, 2025 · 4 comments
Closed

os: Race condition in (* os.File).readdir() #71496

mitmitmitm opened this issue Jan 31, 2025 · 4 comments
Labels
BugReport Issues describing a possible bug in the Go implementation. FixPending Issues that have a fix which has not yet been reviewed or submitted. NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@mitmitmitm
Copy link

Go version

go version go1.23.1 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='~/.cache/go-build'
GOENV='~/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='~/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='~/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.23.1'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='~/.config/go/telemetry'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='~/git/test-proj/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1913440061=/tmp/go-build -gno-record-gcc-switches'

What did you do?

In os/dir_unix.go and in os/dir_plan9.go, (* os.File).readdir() has

func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
	// If this file has no dirInfo, create one.
	d := f.dirinfo.Load()
	if d == nil {
		d = new(dirInfo)
		f.dirinfo.Store(d)
	}
	d.mu.Lock()
	defer d.mu.Unlock()

	// [...]

	for n != 0 {
			// [...]
			d.nbuf, errno = f.pfd.ReadDirent(*d.buf)

This code can execute concurrently in two goroutines such that the condition d == nil is true in both of them. In this case, each goroutine creates and works with a separate instance of d = new(dirInfo), locks a separate mutex d.mu.Lock() and possibly races with the otherone over calls to f.pfd.ReadDirent(*d.buf).

What did you see happen?

/

What did you expect to see?

f.dirinfo.Store(d) should probably use CompareAndSwap instead.

@gabyhelp gabyhelp added the BugReport Issues describing a possible bug in the Go implementation. label Jan 31, 2025
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/645720 mentions this issue: Fix: race condition in readdir by ensuring atomic initialization of d…

@dmitshur dmitshur added NeedsFix The path to resolution is known, but the work has not been done. FixPending Issues that have a fix which has not yet been reviewed or submitted. labels Feb 5, 2025
@dmitshur dmitshur added this to the Go1.25 milestone Feb 5, 2025
@jianfengtony
Copy link

why not backport this issue to old version?

@ianlancetaylor
Copy link
Member

It's not really a race condition, and it's a fairly minor bug. I don't think this meets the guidelines at https://go.dev/wiki/MinorReleases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugReport Issues describing a possible bug in the Go implementation. FixPending Issues that have a fix which has not yet been reviewed or submitted. NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants