From 638b9023e31b2e1d0d8ef24086722388afd76e41 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 31 Jan 2024 14:10:56 -0500 Subject: runtime: be careful about crash FD changes during panic There are two separate cases here: The base case is simple: a concurrent call to SetCrashOutput while panicking will switch the crash FD, which could cause the first half of writes to go to the old FD, and the second half to the new FD. This isn't a correctness problem, but would be annoying to see in practice. Since it is easy to check for, I simply drop any changes if panicking is already in progress. The second case is more important: SetCrashOutput will close the old FD after the new FD is swapped, but writeErrData has no locking around use of the fd, so SetCrashOutput could close the FD out from under writeErrData, causing lost writes. We handle this similarly, by not allowing SetCrashOutput to close the old FD if a panic is in progress, but we have to be more careful about synchronization between writeErrData and setCrashFD to ensure that writeErrData can't observe the old FD while setCrashFD allows close. For #42888. Change-Id: I7270b2cc5ea58a15ba40145b7a96d557acdfe842 Reviewed-on: https://go-review.googlesource.com/c/go/+/559801 Reviewed-by: Alan Donovan Auto-Submit: Michael Pratt Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/runtime/debug/stack.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/runtime/debug/stack.go') diff --git a/src/runtime/debug/stack.go b/src/runtime/debug/stack.go index 7072d29c96..8dfea52d34 100644 --- a/src/runtime/debug/stack.go +++ b/src/runtime/debug/stack.go @@ -38,6 +38,8 @@ func Stack() []byte { // SetCrashOutput duplicates f's file descriptor, so the caller may safely // close f as soon as SetCrashOutput returns. // To disable this additional crash output, call SetCrashOutput(nil). +// If called concurrently with a crash, some in-progress output may be written +// to the old file even after an overriding SetCrashOutput returns. func SetCrashOutput(f *os.File) error { fd := ^uintptr(0) if f != nil { -- cgit v1.3