Source file src/runtime/mfinal.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Garbage collector: finalizers and block profiling.
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/abi"
    11  	"internal/goarch"
    12  	"internal/runtime/atomic"
    13  	"internal/runtime/gc"
    14  	"internal/runtime/sys"
    15  	"unsafe"
    16  )
    17  
    18  const finBlockSize = 4 * 1024
    19  
    20  // finBlock is an block of finalizers to be executed. finBlocks
    21  // are arranged in a linked list for the finalizer queue.
    22  //
    23  // finBlock is allocated from non-GC'd memory, so any heap pointers
    24  // must be specially handled. GC currently assumes that the finalizer
    25  // queue does not grow during marking (but it can shrink).
    26  type finBlock struct {
    27  	_       sys.NotInHeap
    28  	alllink *finBlock
    29  	next    *finBlock
    30  	cnt     uint32
    31  	_       int32
    32  	fin     [(finBlockSize - 2*goarch.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer
    33  }
    34  
    35  var fingStatus atomic.Uint32
    36  
    37  // finalizer goroutine status.
    38  const (
    39  	fingUninitialized uint32 = iota
    40  	fingCreated       uint32 = 1 << (iota - 1)
    41  	fingRunningFinalizer
    42  	fingWait
    43  	fingWake
    44  )
    45  
    46  var (
    47  	finlock     mutex     // protects the following variables
    48  	fing        *g        // goroutine that runs finalizers
    49  	finq        *finBlock // list of finalizers that are to be executed
    50  	finc        *finBlock // cache of free blocks
    51  	finptrmask  [finBlockSize / goarch.PtrSize / 8]byte
    52  	finqueued   uint64 // monotonic count of queued finalizers
    53  	finexecuted uint64 // monotonic count of executed finalizers
    54  )
    55  
    56  var allfin *finBlock // list of all blocks
    57  
    58  // NOTE: Layout known to queuefinalizer.
    59  type finalizer struct {
    60  	fn   *funcval       // function to call (may be a heap pointer)
    61  	arg  unsafe.Pointer // ptr to object (may be a heap pointer)
    62  	nret uintptr        // bytes of return values from fn
    63  	fint *_type         // type of first argument of fn
    64  	ot   *ptrtype       // type of ptr to object (may be a heap pointer)
    65  }
    66  
    67  var finalizer1 = [...]byte{
    68  	// Each Finalizer is 5 words, ptr ptr INT ptr ptr (INT = uintptr here)
    69  	// Each byte describes 8 words.
    70  	// Need 8 Finalizers described by 5 bytes before pattern repeats:
    71  	//	ptr ptr INT ptr ptr
    72  	//	ptr ptr INT ptr ptr
    73  	//	ptr ptr INT ptr ptr
    74  	//	ptr ptr INT ptr ptr
    75  	//	ptr ptr INT ptr ptr
    76  	//	ptr ptr INT ptr ptr
    77  	//	ptr ptr INT ptr ptr
    78  	//	ptr ptr INT ptr ptr
    79  	// aka
    80  	//
    81  	//	ptr ptr INT ptr ptr ptr ptr INT
    82  	//	ptr ptr ptr ptr INT ptr ptr ptr
    83  	//	ptr INT ptr ptr ptr ptr INT ptr
    84  	//	ptr ptr ptr INT ptr ptr ptr ptr
    85  	//	INT ptr ptr ptr ptr INT ptr ptr
    86  	//
    87  	// Assumptions about Finalizer layout checked below.
    88  	1<<0 | 1<<1 | 0<<2 | 1<<3 | 1<<4 | 1<<5 | 1<<6 | 0<<7,
    89  	1<<0 | 1<<1 | 1<<2 | 1<<3 | 0<<4 | 1<<5 | 1<<6 | 1<<7,
    90  	1<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 1<<5 | 0<<6 | 1<<7,
    91  	1<<0 | 1<<1 | 1<<2 | 0<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7,
    92  	0<<0 | 1<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 | 1<<6 | 1<<7,
    93  }
    94  
    95  // lockRankMayQueueFinalizer records the lock ranking effects of a
    96  // function that may call queuefinalizer.
    97  func lockRankMayQueueFinalizer() {
    98  	lockWithRankMayAcquire(&finlock, getLockRank(&finlock))
    99  }
   100  
   101  func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
   102  	if gcphase != _GCoff {
   103  		// Currently we assume that the finalizer queue won't
   104  		// grow during marking so we don't have to rescan it
   105  		// during mark termination. If we ever need to lift
   106  		// this assumption, we can do it by adding the
   107  		// necessary barriers to queuefinalizer (which it may
   108  		// have automatically).
   109  		throw("queuefinalizer during GC")
   110  	}
   111  
   112  	lock(&finlock)
   113  
   114  	if finq == nil || finq.cnt == uint32(len(finq.fin)) {
   115  		if finc == nil {
   116  			finc = (*finBlock)(persistentalloc(finBlockSize, 0, &memstats.gcMiscSys))
   117  			finc.alllink = allfin
   118  			allfin = finc
   119  			if finptrmask[0] == 0 {
   120  				// Build pointer mask for Finalizer array in block.
   121  				// Check assumptions made in finalizer1 array above.
   122  				if (unsafe.Sizeof(finalizer{}) != 5*goarch.PtrSize ||
   123  					unsafe.Offsetof(finalizer{}.fn) != 0 ||
   124  					unsafe.Offsetof(finalizer{}.arg) != goarch.PtrSize ||
   125  					unsafe.Offsetof(finalizer{}.nret) != 2*goarch.PtrSize ||
   126  					unsafe.Offsetof(finalizer{}.fint) != 3*goarch.PtrSize ||
   127  					unsafe.Offsetof(finalizer{}.ot) != 4*goarch.PtrSize) {
   128  					throw("finalizer out of sync")
   129  				}
   130  				for i := range finptrmask {
   131  					finptrmask[i] = finalizer1[i%len(finalizer1)]
   132  				}
   133  			}
   134  		}
   135  		block := finc
   136  		finc = block.next
   137  		block.next = finq
   138  		finq = block
   139  	}
   140  	f := &finq.fin[finq.cnt]
   141  	atomic.Xadd(&finq.cnt, +1) // Sync with markroots
   142  	f.fn = fn
   143  	f.nret = nret
   144  	f.fint = fint
   145  	f.ot = ot
   146  	f.arg = p
   147  	finqueued++
   148  	unlock(&finlock)
   149  	fingStatus.Or(fingWake)
   150  }
   151  
   152  //go:nowritebarrier
   153  func iterate_finq(callback func(*funcval, unsafe.Pointer, uintptr, *_type, *ptrtype)) {
   154  	for fb := allfin; fb != nil; fb = fb.alllink {
   155  		for i := uint32(0); i < fb.cnt; i++ {
   156  			f := &fb.fin[i]
   157  			callback(f.fn, f.arg, f.nret, f.fint, f.ot)
   158  		}
   159  	}
   160  }
   161  
   162  func wakefing() *g {
   163  	if ok := fingStatus.CompareAndSwap(fingCreated|fingWait|fingWake, fingCreated); ok {
   164  		return fing
   165  	}
   166  	return nil
   167  }
   168  
   169  func createfing() {
   170  	// start the finalizer goroutine exactly once
   171  	if fingStatus.Load() == fingUninitialized && fingStatus.CompareAndSwap(fingUninitialized, fingCreated) {
   172  		go runFinalizers()
   173  	}
   174  }
   175  
   176  func finalizercommit(gp *g, lock unsafe.Pointer) bool {
   177  	unlock((*mutex)(lock))
   178  	// fingStatus should be modified after fing is put into a waiting state
   179  	// to avoid waking fing in running state, even if it is about to be parked.
   180  	fingStatus.Or(fingWait)
   181  	return true
   182  }
   183  
   184  func finReadQueueStats() (queued, executed uint64) {
   185  	lock(&finlock)
   186  	queued = finqueued
   187  	executed = finexecuted
   188  	unlock(&finlock)
   189  	return
   190  }
   191  
   192  // This is the goroutine that runs all of the finalizers.
   193  func runFinalizers() {
   194  	var (
   195  		frame    unsafe.Pointer
   196  		framecap uintptr
   197  		argRegs  int
   198  	)
   199  
   200  	gp := getg()
   201  	lock(&finlock)
   202  	fing = gp
   203  	unlock(&finlock)
   204  
   205  	for {
   206  		lock(&finlock)
   207  		fb := finq
   208  		finq = nil
   209  		if fb == nil {
   210  			gopark(finalizercommit, unsafe.Pointer(&finlock), waitReasonFinalizerWait, traceBlockSystemGoroutine, 1)
   211  			continue
   212  		}
   213  		argRegs = intArgRegs
   214  		unlock(&finlock)
   215  		if raceenabled {
   216  			racefingo()
   217  		}
   218  		for fb != nil {
   219  			n := fb.cnt
   220  			for i := n; i > 0; i-- {
   221  				f := &fb.fin[i-1]
   222  
   223  				var regs abi.RegArgs
   224  				// The args may be passed in registers or on stack. Even for
   225  				// the register case, we still need the spill slots.
   226  				// TODO: revisit if we remove spill slots.
   227  				//
   228  				// Unfortunately because we can have an arbitrary
   229  				// amount of returns and it would be complex to try and
   230  				// figure out how many of those can get passed in registers,
   231  				// just conservatively assume none of them do.
   232  				framesz := unsafe.Sizeof((any)(nil)) + f.nret
   233  				if framecap < framesz {
   234  					// The frame does not contain pointers interesting for GC,
   235  					// all not yet finalized objects are stored in finq.
   236  					// If we do not mark it as FlagNoScan,
   237  					// the last finalized object is not collected.
   238  					frame = mallocgc(framesz, nil, true)
   239  					framecap = framesz
   240  				}
   241  				if f.fint == nil {
   242  					throw("missing type in finalizer")
   243  				}
   244  				r := frame
   245  				if argRegs > 0 {
   246  					r = unsafe.Pointer(&regs.Ints)
   247  				} else {
   248  					// frame is effectively uninitialized
   249  					// memory. That means we have to clear
   250  					// it before writing to it to avoid
   251  					// confusing the write barrier.
   252  					*(*[2]uintptr)(frame) = [2]uintptr{}
   253  				}
   254  				switch f.fint.Kind_ & abi.KindMask {
   255  				case abi.Pointer:
   256  					// direct use of pointer
   257  					*(*unsafe.Pointer)(r) = f.arg
   258  				case abi.Interface:
   259  					ityp := (*interfacetype)(unsafe.Pointer(f.fint))
   260  					// set up with empty interface
   261  					(*eface)(r)._type = &f.ot.Type
   262  					(*eface)(r).data = f.arg
   263  					if len(ityp.Methods) != 0 {
   264  						// convert to interface with methods
   265  						// this conversion is guaranteed to succeed - we checked in SetFinalizer
   266  						(*iface)(r).tab = assertE2I(ityp, (*eface)(r)._type)
   267  					}
   268  				default:
   269  					throw("bad type kind in finalizer")
   270  				}
   271  				fingStatus.Or(fingRunningFinalizer)
   272  				reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz), uint32(framesz), &regs)
   273  				fingStatus.And(^fingRunningFinalizer)
   274  
   275  				// Drop finalizer queue heap references
   276  				// before hiding them from markroot.
   277  				// This also ensures these will be
   278  				// clear if we reuse the finalizer.
   279  				f.fn = nil
   280  				f.arg = nil
   281  				f.ot = nil
   282  				atomic.Store(&fb.cnt, i-1)
   283  			}
   284  			next := fb.next
   285  			lock(&finlock)
   286  			finexecuted += uint64(n)
   287  			fb.next = finc
   288  			finc = fb
   289  			unlock(&finlock)
   290  			fb = next
   291  		}
   292  	}
   293  }
   294  
   295  func isGoPointerWithoutSpan(p unsafe.Pointer) bool {
   296  	// 0-length objects are okay.
   297  	if p == unsafe.Pointer(&zerobase) {
   298  		return true
   299  	}
   300  
   301  	// Global initializers might be linker-allocated.
   302  	//	var Foo = &Object{}
   303  	//	func main() {
   304  	//		runtime.SetFinalizer(Foo, nil)
   305  	//	}
   306  	// The relevant segments are: noptrdata, data, bss, noptrbss.
   307  	// We cannot assume they are in any order or even contiguous,
   308  	// due to external linking.
   309  	for datap := &firstmoduledata; datap != nil; datap = datap.next {
   310  		if datap.noptrdata <= uintptr(p) && uintptr(p) < datap.enoptrdata ||
   311  			datap.data <= uintptr(p) && uintptr(p) < datap.edata ||
   312  			datap.bss <= uintptr(p) && uintptr(p) < datap.ebss ||
   313  			datap.noptrbss <= uintptr(p) && uintptr(p) < datap.enoptrbss {
   314  			return true
   315  		}
   316  	}
   317  	return false
   318  }
   319  
   320  // blockUntilEmptyFinalizerQueue blocks until either the finalizer
   321  // queue is emptied (and the finalizers have executed) or the timeout
   322  // is reached. Returns true if the finalizer queue was emptied.
   323  // This is used by the runtime, sync, and unique tests.
   324  func blockUntilEmptyFinalizerQueue(timeout int64) bool {
   325  	start := nanotime()
   326  	for nanotime()-start < timeout {
   327  		lock(&finlock)
   328  		// We know the queue has been drained when both finq is nil
   329  		// and the finalizer g has stopped executing.
   330  		empty := finq == nil
   331  		empty = empty && readgstatus(fing) == _Gwaiting && fing.waitreason == waitReasonFinalizerWait
   332  		unlock(&finlock)
   333  		if empty {
   334  			return true
   335  		}
   336  		Gosched()
   337  	}
   338  	return false
   339  }
   340  
   341  // SetFinalizer sets the finalizer associated with obj to the provided
   342  // finalizer function. When the garbage collector finds an unreachable block
   343  // with an associated finalizer, it clears the association and runs
   344  // finalizer(obj) in a separate goroutine. This makes obj reachable again,
   345  // but now without an associated finalizer. Assuming that SetFinalizer
   346  // is not called again, the next time the garbage collector sees
   347  // that obj is unreachable, it will free obj.
   348  //
   349  // SetFinalizer(obj, nil) clears any finalizer associated with obj.
   350  //
   351  // New Go code should consider using [AddCleanup] instead, which is much
   352  // less error-prone than SetFinalizer.
   353  //
   354  // The argument obj must be a pointer to an object allocated by calling
   355  // new, by taking the address of a composite literal, or by taking the
   356  // address of a local variable.
   357  // The argument finalizer must be a function that takes a single argument
   358  // to which obj's type can be assigned, and can have arbitrary ignored return
   359  // values. If either of these is not true, SetFinalizer may abort the
   360  // program.
   361  //
   362  // Finalizers are run in dependency order: if A points at B, both have
   363  // finalizers, and they are otherwise unreachable, only the finalizer
   364  // for A runs; once A is freed, the finalizer for B can run.
   365  // If a cyclic structure includes a block with a finalizer, that
   366  // cycle is not guaranteed to be garbage collected and the finalizer
   367  // is not guaranteed to run, because there is no ordering that
   368  // respects the dependencies.
   369  //
   370  // The finalizer is scheduled to run at some arbitrary time after the
   371  // program can no longer reach the object to which obj points.
   372  // There is no guarantee that finalizers will run before a program exits,
   373  // so typically they are useful only for releasing non-memory resources
   374  // associated with an object during a long-running program.
   375  // For example, an [os.File] object could use a finalizer to close the
   376  // associated operating system file descriptor when a program discards
   377  // an os.File without calling Close, but it would be a mistake
   378  // to depend on a finalizer to flush an in-memory I/O buffer such as a
   379  // [bufio.Writer], because the buffer would not be flushed at program exit.
   380  //
   381  // It is not guaranteed that a finalizer will run if the size of *obj is
   382  // zero bytes, because it may share same address with other zero-size
   383  // objects in memory. See https://go.dev/ref/spec#Size_and_alignment_guarantees.
   384  //
   385  // It is not guaranteed that a finalizer will run for objects allocated
   386  // in initializers for package-level variables. Such objects may be
   387  // linker-allocated, not heap-allocated.
   388  //
   389  // Note that because finalizers may execute arbitrarily far into the future
   390  // after an object is no longer referenced, the runtime is allowed to perform
   391  // a space-saving optimization that batches objects together in a single
   392  // allocation slot. The finalizer for an unreferenced object in such an
   393  // allocation may never run if it always exists in the same batch as a
   394  // referenced object. Typically, this batching only happens for tiny
   395  // (on the order of 16 bytes or less) and pointer-free objects.
   396  //
   397  // A finalizer may run as soon as an object becomes unreachable.
   398  // In order to use finalizers correctly, the program must ensure that
   399  // the object is reachable until it is no longer required.
   400  // Objects stored in global variables, or that can be found by tracing
   401  // pointers from a global variable, are reachable. A function argument or
   402  // receiver may become unreachable at the last point where the function
   403  // mentions it. To make an unreachable object reachable, pass the object
   404  // to a call of the [KeepAlive] function to mark the last point in the
   405  // function where the object must be reachable.
   406  //
   407  // For example, if p points to a struct, such as os.File, that contains
   408  // a file descriptor d, and p has a finalizer that closes that file
   409  // descriptor, and if the last use of p in a function is a call to
   410  // syscall.Write(p.d, buf, size), then p may be unreachable as soon as
   411  // the program enters [syscall.Write]. The finalizer may run at that moment,
   412  // closing p.d, causing syscall.Write to fail because it is writing to
   413  // a closed file descriptor (or, worse, to an entirely different
   414  // file descriptor opened by a different goroutine). To avoid this problem,
   415  // call KeepAlive(p) after the call to syscall.Write.
   416  //
   417  // A single goroutine runs all finalizers for a program, sequentially.
   418  // If a finalizer must run for a long time, it should do so by starting
   419  // a new goroutine.
   420  //
   421  // In the terminology of the Go memory model, a call
   422  // SetFinalizer(x, f) “synchronizes before” the finalization call f(x).
   423  // However, there is no guarantee that KeepAlive(x) or any other use of x
   424  // “synchronizes before” f(x), so in general a finalizer should use a mutex
   425  // or other synchronization mechanism if it needs to access mutable state in x.
   426  // For example, consider a finalizer that inspects a mutable field in x
   427  // that is modified from time to time in the main program before x
   428  // becomes unreachable and the finalizer is invoked.
   429  // The modifications in the main program and the inspection in the finalizer
   430  // need to use appropriate synchronization, such as mutexes or atomic updates,
   431  // to avoid read-write races.
   432  func SetFinalizer(obj any, finalizer any) {
   433  	e := efaceOf(&obj)
   434  	etyp := e._type
   435  	if etyp == nil {
   436  		throw("runtime.SetFinalizer: first argument is nil")
   437  	}
   438  	if etyp.Kind_&abi.KindMask != abi.Pointer {
   439  		throw("runtime.SetFinalizer: first argument is " + toRType(etyp).string() + ", not pointer")
   440  	}
   441  	ot := (*ptrtype)(unsafe.Pointer(etyp))
   442  	if ot.Elem == nil {
   443  		throw("nil elem type!")
   444  	}
   445  	if inUserArenaChunk(uintptr(e.data)) {
   446  		// Arena-allocated objects are not eligible for finalizers.
   447  		throw("runtime.SetFinalizer: first argument was allocated into an arena")
   448  	}
   449  	if debug.sbrk != 0 {
   450  		// debug.sbrk never frees memory, so no finalizers run
   451  		// (and we don't have the data structures to record them).
   452  		return
   453  	}
   454  
   455  	// find the containing object
   456  	base, span, _ := findObject(uintptr(e.data), 0, 0)
   457  
   458  	if base == 0 {
   459  		if isGoPointerWithoutSpan(e.data) {
   460  			return
   461  		}
   462  		throw("runtime.SetFinalizer: pointer not in allocated block")
   463  	}
   464  
   465  	// Move base forward if we've got an allocation header.
   466  	if !span.spanclass.noscan() && !heapBitsInSpan(span.elemsize) && span.spanclass.sizeclass() != 0 {
   467  		base += gc.MallocHeaderSize
   468  	}
   469  
   470  	if uintptr(e.data) != base {
   471  		// As an implementation detail we allow to set finalizers for an inner byte
   472  		// of an object if it could come from tiny alloc (see mallocgc for details).
   473  		if ot.Elem == nil || ot.Elem.Pointers() || ot.Elem.Size_ >= maxTinySize {
   474  			throw("runtime.SetFinalizer: pointer not at beginning of allocated block")
   475  		}
   476  	}
   477  
   478  	f := efaceOf(&finalizer)
   479  	ftyp := f._type
   480  	if ftyp == nil {
   481  		// switch to system stack and remove finalizer
   482  		systemstack(func() {
   483  			removefinalizer(e.data)
   484  
   485  			if debug.checkfinalizers != 0 {
   486  				clearFinalizerContext(uintptr(e.data))
   487  				KeepAlive(e.data)
   488  			}
   489  		})
   490  		return
   491  	}
   492  
   493  	if ftyp.Kind_&abi.KindMask != abi.Func {
   494  		throw("runtime.SetFinalizer: second argument is " + toRType(ftyp).string() + ", not a function")
   495  	}
   496  	ft := (*functype)(unsafe.Pointer(ftyp))
   497  	if ft.IsVariadic() {
   498  		throw("runtime.SetFinalizer: cannot pass " + toRType(etyp).string() + " to finalizer " + toRType(ftyp).string() + " because dotdotdot")
   499  	}
   500  	if ft.InCount != 1 {
   501  		throw("runtime.SetFinalizer: cannot pass " + toRType(etyp).string() + " to finalizer " + toRType(ftyp).string())
   502  	}
   503  	fint := ft.InSlice()[0]
   504  	switch {
   505  	case fint == etyp:
   506  		// ok - same type
   507  		goto okarg
   508  	case fint.Kind_&abi.KindMask == abi.Pointer:
   509  		if (fint.Uncommon() == nil || etyp.Uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).Elem == ot.Elem {
   510  			// ok - not same type, but both pointers,
   511  			// one or the other is unnamed, and same element type, so assignable.
   512  			goto okarg
   513  		}
   514  	case fint.Kind_&abi.KindMask == abi.Interface:
   515  		ityp := (*interfacetype)(unsafe.Pointer(fint))
   516  		if len(ityp.Methods) == 0 {
   517  			// ok - satisfies empty interface
   518  			goto okarg
   519  		}
   520  		if itab := assertE2I2(ityp, efaceOf(&obj)._type); itab != nil {
   521  			goto okarg
   522  		}
   523  	}
   524  	throw("runtime.SetFinalizer: cannot pass " + toRType(etyp).string() + " to finalizer " + toRType(ftyp).string())
   525  okarg:
   526  	// compute size needed for return parameters
   527  	nret := uintptr(0)
   528  	for _, t := range ft.OutSlice() {
   529  		nret = alignUp(nret, uintptr(t.Align_)) + t.Size_
   530  	}
   531  	nret = alignUp(nret, goarch.PtrSize)
   532  
   533  	// make sure we have a finalizer goroutine
   534  	createfing()
   535  
   536  	callerpc := sys.GetCallerPC()
   537  	systemstack(func() {
   538  		if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
   539  			throw("runtime.SetFinalizer: finalizer already set")
   540  		}
   541  		if debug.checkfinalizers != 0 {
   542  			setFinalizerContext(e.data, ot.Elem, callerpc, (*funcval)(f.data).fn)
   543  		}
   544  	})
   545  }
   546  
   547  // Mark KeepAlive as noinline so that it is easily detectable as an intrinsic.
   548  //
   549  //go:noinline
   550  
   551  // KeepAlive marks its argument as currently reachable.
   552  // This ensures that the object is not freed, and its finalizer is not run,
   553  // before the point in the program where KeepAlive is called.
   554  //
   555  // A very simplified example showing where KeepAlive is required:
   556  //
   557  //	type File struct { d int }
   558  //	d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0)
   559  //	// ... do something if err != nil ...
   560  //	p := &File{d}
   561  //	runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) })
   562  //	var buf [10]byte
   563  //	n, err := syscall.Read(p.d, buf[:])
   564  //	// Ensure p is not finalized until Read returns.
   565  //	runtime.KeepAlive(p)
   566  //	// No more uses of p after this point.
   567  //
   568  // Without the KeepAlive call, the finalizer could run at the start of
   569  // [syscall.Read], closing the file descriptor before syscall.Read makes
   570  // the actual system call.
   571  //
   572  // Note: KeepAlive should only be used to prevent finalizers from
   573  // running prematurely. In particular, when used with [unsafe.Pointer],
   574  // the rules for valid uses of unsafe.Pointer still apply.
   575  func KeepAlive(x any) {
   576  	// Introduce a use of x that the compiler can't eliminate.
   577  	// This makes sure x is alive on entry. We need x to be alive
   578  	// on entry for "defer runtime.KeepAlive(x)"; see issue 21402.
   579  	if cgoAlwaysFalse {
   580  		println(x)
   581  	}
   582  }
   583  

View as plain text