1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:30:07 -07:00

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 <r@golang.org>
Trust: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Changkun Ou 2020-09-24 08:57:00 +02:00 committed by Rob Pike
parent 6f02578f9c
commit 7bb6fed9b5
4 changed files with 28 additions and 15 deletions

View File

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

View File

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

View File

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

View File

@ -293,15 +293,15 @@ func runfinq() {
// pass the object to a call of the KeepAlive function to mark the
// last point in the function where the object must be reachable.
//
// For example, if p points to a struct that contains a file descriptor d,
// and p has a finalizer that closes that file descriptor, and if the last
// use of p in a function is a call to syscall.Write(p.d, buf, size), then
// p may be unreachable as soon as the program enters syscall.Write. The
// finalizer may run at that moment, closing p.d, causing syscall.Write
// to fail because it is writing to a closed file descriptor (or, worse,
// to an entirely different file descriptor opened by a different goroutine).
// To avoid this problem, call runtime.KeepAlive(p) after the call to
// syscall.Write.
// For example, if p points to a struct, such as os.File, that contains
// a file descriptor d, and p has a finalizer that closes that file
// descriptor, and if the last use of p in a function is a call to
// syscall.Write(p.d, buf, size), then p may be unreachable as soon as
// the program enters syscall.Write. The finalizer may run at that moment,
// closing p.d, causing syscall.Write to fail because it is writing to
// a closed file descriptor (or, worse, to an entirely different
// file descriptor opened by a different goroutine). To avoid this problem,
// call runtime.KeepAlive(p) after the call to syscall.Write.
//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting