os: further document limitations around naked file descriptors

NewFile requires the file descriptor to be either closed
through the returned File instance, or to stay valid at least
until the finalizer runs during garbage collection.

These requirements are easily violated when file descriptors
are closed via unix.Close, or when the *File returned by
NewFile is garbage collected while the underlying file descriptor is
still in use.

This commit adds further documentation for NewFile and Fd, making it
explicit that using naked file descriptors is subject to constraints
due to garbage collection of File objects.

Fixes #43863
This commit is contained in:
Victor Michel 2021-01-23 02:12:43 -08:00
parent 66ee8b158f
commit 180d0130ae
1 changed files with 8 additions and 0 deletions

View File

@ -66,6 +66,10 @@ type file struct {
// making it invalid; see runtime.SetFinalizer for more information on when // making it invalid; see runtime.SetFinalizer for more information on when
// a finalizer might be run. On Unix systems this will cause the SetDeadline // a finalizer might be run. On Unix systems this will cause the SetDeadline
// methods to stop working. // methods to stop working.
// Because file descriptors can be reused, the returned file descriptor may
// only be closed through the Close method of f, or by its finalizer during
// garbage collection. Otherwise, during garbage collection the finalizer
// may close an unrelated file descriptor with the same (reused) number.
// //
// As an alternative, see the f.SyscallConn method. // As an alternative, see the f.SyscallConn method.
func (f *File) Fd() uintptr { func (f *File) Fd() uintptr {
@ -90,6 +94,10 @@ func (f *File) Fd() uintptr {
// descriptor. On Unix systems, if the file descriptor is in // descriptor. On Unix systems, if the file descriptor is in
// non-blocking mode, NewFile will attempt to return a pollable File // non-blocking mode, NewFile will attempt to return a pollable File
// (one for which the SetDeadline methods work). // (one for which the SetDeadline methods work).
//
// After passing it to NewFile, fd may become invalid under the same
// conditions described in the comments of the Fd method, and the same
// constraints apply.
func NewFile(fd uintptr, name string) *File { func NewFile(fd uintptr, name string) *File {
kind := kindNewFile kind := kindNewFile
if nb, err := unix.IsNonblock(int(fd)); err == nil && nb { if nb, err := unix.IsNonblock(int(fd)); err == nil && nb {