Skip to content

Commit 7bb6fed

Browse files
changkunrobpike
authored andcommitted
os: document and emphasize a potential misuse of File.Fd
This CL revises the document of File.Fd that explicitly points its user to runtime.SetFinalizer where contains the information that a file descriptor could be closed in a finalizer and therefore causes a failure in syscall.Write if runtime.KeepAlive is not invoked. The CL also suggests an alternative of File.Fd towards File.SyscallConn. Fixes #41505 Change-Id: I6816f0157add48b649bf1fb793cf19dcea6894b5 Reviewed-on: https://go-review.googlesource.com/c/go/+/256899 Reviewed-by: Rob Pike <[email protected]> Trust: Ian Lance Taylor <[email protected]>
1 parent 6f02578 commit 7bb6fed

File tree

4 files changed

+28
-15
lines changed

4 files changed

+28
-15
lines changed

src/os/file_plan9.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@ type file struct {
2929
}
3030

3131
// Fd returns the integer Plan 9 file descriptor referencing the open file.
32-
// The file descriptor is valid only until f.Close is called or f is garbage collected.
33-
// On Unix systems this will cause the SetDeadline methods to stop working.
32+
// If f is closed, the file descriptor becomes invalid.
33+
// If f is garbage collected, a finalizer may close the file descriptor,
34+
// making it invalid; see runtime.SetFinalizer for more information on when
35+
// a finalizer might be run. On Unix systems this will cause the SetDeadline
36+
// methods to stop working.
37+
//
38+
// As an alternative, see the f.SyscallCon method.
3439
func (f *File) Fd() uintptr {
3540
if f == nil {
3641
return ^(uintptr(0))

src/os/file_unix.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,13 @@ type file struct {
6262
}
6363

6464
// Fd returns the integer Unix file descriptor referencing the open file.
65-
// The file descriptor is valid only until f.Close is called or f is garbage collected.
66-
// On Unix systems this will cause the SetDeadline methods to stop working.
65+
// If f is closed, the file descriptor becomes invalid.
66+
// If f is garbage collected, a finalizer may close the file descriptor,
67+
// making it invalid; see runtime.SetFinalizer for more information on when
68+
// a finalizer might be run. On Unix systems this will cause the SetDeadline
69+
// methods to stop working.
70+
//
71+
// As an alternative, see the f.SyscallCon method.
6772
func (f *File) Fd() uintptr {
6873
if f == nil {
6974
return ^(uintptr(0))

src/os/file_windows.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ type file struct {
2626
}
2727

2828
// Fd returns the Windows handle referencing the open file.
29-
// The handle is valid only until f.Close is called or f is garbage collected.
30-
// On Unix systems this will cause the SetDeadline methods to stop working.
29+
// If f is closed, the file descriptor becomes invalid.
30+
// If f is garbage collected, a finalizer may close the file descriptor,
31+
// making it invalid; see runtime.SetFinalizer for more information on when
32+
// a finalizer might be run. On Unix systems this will cause the SetDeadline
33+
// methods to stop working.
3134
func (file *File) Fd() uintptr {
3235
if file == nil {
3336
return uintptr(syscall.InvalidHandle)

src/runtime/mfinal.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -293,15 +293,15 @@ func runfinq() {
293293
// pass the object to a call of the KeepAlive function to mark the
294294
// last point in the function where the object must be reachable.
295295
//
296-
// For example, if p points to a struct that contains a file descriptor d,
297-
// and p has a finalizer that closes that file descriptor, and if the last
298-
// use of p in a function is a call to syscall.Write(p.d, buf, size), then
299-
// p may be unreachable as soon as the program enters syscall.Write. The
300-
// finalizer may run at that moment, closing p.d, causing syscall.Write
301-
// to fail because it is writing to a closed file descriptor (or, worse,
302-
// to an entirely different file descriptor opened by a different goroutine).
303-
// To avoid this problem, call runtime.KeepAlive(p) after the call to
304-
// syscall.Write.
296+
// For example, if p points to a struct, such as os.File, that contains
297+
// a file descriptor d, and p has a finalizer that closes that file
298+
// descriptor, and if the last use of p in a function is a call to
299+
// syscall.Write(p.d, buf, size), then p may be unreachable as soon as
300+
// the program enters syscall.Write. The finalizer may run at that moment,
301+
// closing p.d, causing syscall.Write to fail because it is writing to
302+
// a closed file descriptor (or, worse, to an entirely different
303+
// file descriptor opened by a different goroutine). To avoid this problem,
304+
// call runtime.KeepAlive(p) after the call to syscall.Write.
305305
//
306306
// A single goroutine runs all finalizers for a program, sequentially.
307307
// If a finalizer must run for a long time, it should do so by starting

0 commit comments

Comments
 (0)