Skip to content

Commit be2b809

Browse files
Mehrbod2002gopherbot
authored andcommitted
os: fix race condition in readdir by atomically initializing dirinfo
This change ensures that dirinfo in the File struct is initialized atomically, avoiding redundant allocations when multiple goroutines access it concurrently. Instead of creating separate buffers, we now use CompareAndSwap to guarantee thread-safe initialization and reduce unnecessary memory usage. Although this is not a strict race condition, the update enhances efficiency by eliminating duplicate allocations and ensuring safer concurrent access. Fixes #71496. Change-Id: If08699a94afa05611cdf67e82a5957a8d8f9d5c8 GitHub-Last-Rev: 1e1f619 GitHub-Pull-Request: #71501 Reviewed-on: https://go-review.googlesource.com/c/go/+/645720 Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent a1ea78c commit be2b809

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

src/os/dir_plan9.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,19 @@ import (
1111
)
1212

1313
func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
14-
// If this file has no dirinfo, create one.
15-
d := file.dirinfo.Load()
16-
if d == nil {
17-
d = new(dirInfo)
18-
file.dirinfo.Store(d)
14+
var d *dirInfo
15+
for {
16+
d = file.dirinfo.Load()
17+
if d != nil {
18+
break
19+
}
20+
newD := new(dirInfo)
21+
if file.dirinfo.CompareAndSwap(nil, newD) {
22+
d = newD
23+
break
24+
}
1925
}
26+
2027
d.mu.Lock()
2128
defer d.mu.Unlock()
2229

src/os/dir_unix.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,19 @@ func (d *dirInfo) close() {
4646

4747
func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
4848
// If this file has no dirInfo, create one.
49-
d := f.dirinfo.Load()
50-
if d == nil {
51-
d = new(dirInfo)
52-
f.dirinfo.Store(d)
49+
var d *dirInfo
50+
for {
51+
d = f.dirinfo.Load()
52+
if d != nil {
53+
break
54+
}
55+
newD := new(dirInfo)
56+
if f.dirinfo.CompareAndSwap(nil, newD) {
57+
d = newD
58+
break
59+
}
5360
}
61+
5462
d.mu.Lock()
5563
defer d.mu.Unlock()
5664
if d.buf == nil {

0 commit comments

Comments
 (0)