Skip to content

Commit 54da0a0

Browse files
lmbti-mo
andcommitted
all: use runtime.AddCleanup
Convert all uses of runtime.SetFinalizer to runtime.AddCleanup. The exception is the unsafe memory code, which cannot currently be converted due to fundamental differences with finalizers. Cleanups cannot carry references to the object in question, and cannot resurrect the object, meaning the original object's allocation can be used to service new allocations before the cleanup has run. In our case, this means bpf map memory gets zeroed by the allocator, which is obviously a show stopper. If we want to move off finalizers, we need to implement golang/go#70224 first and switch to that instead. Signed-off-by: Lorenz Bauer <[email protected]> Co-authored-by: Timo Beckers <[email protected]>
1 parent 456b77f commit 54da0a0

File tree

12 files changed

+61
-44
lines changed

12 files changed

+61
-44
lines changed

btf/kernel.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ func loadKernelSpec() (*Spec, error) {
151151
return nil, fmt.Errorf("load vmlinux: %w", err)
152152
}
153153

154-
runtime.SetFinalizer(spec.decoder.sharedBuf, func(_ *sharedBuf) {
155-
_ = unix.Munmap(raw)
156-
})
154+
runtime.AddCleanup(spec.decoder.sharedBuf, func(b []byte) {
155+
_ = unix.Munmap(b)
156+
}, raw)
157157

158158
return spec, nil
159159
}

internal/epoll/poller.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Poller struct {
3434
eventMu sync.Mutex
3535
closeEvent *eventFd
3636
flushEvent *eventFd
37+
cleanup runtime.Cleanup
3738
}
3839

3940
func New() (_ *Poller, err error) {
@@ -75,7 +76,10 @@ func New() (_ *Poller, err error) {
7576
return nil, fmt.Errorf("add flush eventfd: %w", err)
7677
}
7778

78-
runtime.SetFinalizer(p, (*Poller).Close)
79+
p.cleanup = runtime.AddCleanup(p, func(raw int) {
80+
_ = unix.Close(raw)
81+
}, p.epollFd)
82+
7983
return p, nil
8084
}
8185

@@ -84,7 +88,7 @@ func New() (_ *Poller, err error) {
8488
// Interrupts any calls to Wait. Multiple calls to Close are valid, but subsequent
8589
// calls will return os.ErrClosed.
8690
func (p *Poller) Close() error {
87-
runtime.SetFinalizer(p, nil)
91+
p.cleanup.Stop()
8892

8993
// Interrupt Wait() via the closeEvent fd if it's currently blocked.
9094
if err := p.wakeWaitForClose(); err != nil {

internal/sys/fd.go

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,14 @@ const invalidFd = -1
2121
func newFD(value int) *FD {
2222
testmain.TraceFD(value, 1)
2323

24-
fd := &FD{value}
25-
runtime.SetFinalizer(fd, (*FD).finalize)
24+
fd := &FD{raw: value}
25+
fd.cleanup = runtime.AddCleanup(fd, func(raw int) {
26+
testmain.LeakFD(raw)
27+
_ = unix.Close(raw)
28+
}, fd.raw)
2629
return fd
2730
}
2831

29-
// finalize is set as the FD's runtime finalizer and
30-
// sends a leak trace before calling FD.Close().
31-
func (fd *FD) finalize() {
32-
if fd.raw == invalidFd {
33-
return
34-
}
35-
36-
testmain.LeakFD(fd.raw)
37-
38-
_ = fd.Close()
39-
}
40-
4132
func (fd *FD) String() string {
4233
return strconv.FormatInt(int64(fd.raw), 10)
4334
}
@@ -63,6 +54,6 @@ func (fd *FD) Disown() int {
6354
testmain.ForgetFD(value)
6455
fd.raw = invalidFd
6556

66-
runtime.SetFinalizer(fd, nil)
57+
fd.cleanup.Stop()
6758
return value
6859
}

internal/sys/fd_other.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ package sys
55
import (
66
"fmt"
77
"os"
8+
"runtime"
89

910
"github.com/cilium/ebpf/internal/unix"
1011
)
1112

1213
type FD struct {
13-
raw int
14+
raw int
15+
cleanup runtime.Cleanup
1416
}
1517

1618
// NewFD wraps a raw fd with a finalizer.

internal/sys/fd_windows.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package sys
33
import (
44
"fmt"
55
"os"
6+
"runtime"
67

78
"github.com/cilium/ebpf/internal"
89
"github.com/cilium/ebpf/internal/efw"
@@ -12,7 +13,8 @@ import (
1213
//
1314
// It is not equivalent to a real file descriptor or handle.
1415
type FD struct {
15-
raw int
16+
raw int
17+
cleanup runtime.Cleanup
1618
}
1719

1820
// NewFD wraps a raw fd with a finalizer.

internal/tracefs/kprobe.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ type Event struct {
200200
group, name string
201201
// event id allocated by the kernel. 0 if the event has already been removed.
202202
id uint64
203+
204+
cleanup runtime.Cleanup
203205
}
204206

205207
// NewEvent creates a new ephemeral trace event.
@@ -316,8 +318,11 @@ func NewEvent(args ProbeArgs) (*Event, error) {
316318
return nil, fmt.Errorf("get trace event id: %w", err)
317319
}
318320

319-
evt := &Event{args.Type, args.Group, eventName, tid}
320-
runtime.SetFinalizer(evt, (*Event).Close)
321+
evt := &Event{typ: args.Type, group: args.Group, name: eventName, id: tid}
322+
evt.cleanup = runtime.AddCleanup(evt, func(*byte) {
323+
_ = removeEvent(args.Type, fmt.Sprintf("%s/%s", args.Group, eventName))
324+
}, nil)
325+
321326
return evt, nil
322327
}
323328

@@ -330,7 +335,7 @@ func (evt *Event) Close() error {
330335
}
331336

332337
evt.id = 0
333-
runtime.SetFinalizer(evt, nil)
338+
evt.cleanup.Stop()
334339
pe := fmt.Sprintf("%s/%s", evt.group, evt.name)
335340
return removeEvent(evt.typ, pe)
336341
}

memory.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ type Memory struct {
3838
b []byte
3939
ro bool
4040
heap bool
41+
42+
cleanup runtime.Cleanup
4143
}
4244

4345
func newMemory(fd, size int) (*Memory, error) {
@@ -62,20 +64,23 @@ func newMemory(fd, size int) (*Memory, error) {
6264
return nil, fmt.Errorf("setting up memory-mapped region: %w", err)
6365
}
6466

65-
mm := &Memory{
66-
b,
67-
ro,
68-
false,
69-
}
70-
runtime.SetFinalizer(mm, (*Memory).close)
67+
mm := &Memory{b: b, ro: ro, heap: false}
68+
mm.cleanup = runtime.AddCleanup(&mm, memoryCleanupFunc(), b)
7169

7270
return mm, nil
7371
}
7472

75-
func (mm *Memory) close() {
76-
if err := unix.Munmap(mm.b); err != nil {
77-
panic(fmt.Errorf("unmapping memory: %w", err))
73+
func memoryCleanupFunc() func([]byte) {
74+
return func(b []byte) {
75+
if err := unix.Munmap(b); err != nil {
76+
panic(fmt.Errorf("unmapping memory: %w", err))
77+
}
7878
}
79+
}
80+
81+
func (mm *Memory) close() {
82+
mm.cleanup.Stop()
83+
memoryCleanupFunc()(mm.b)
7984
mm.b = nil
8085
}
8186

memory_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"io"
55
"math"
66
"os"
7-
"runtime"
87
"testing"
98

109
"github.com/go-quicktest/qt"
@@ -88,9 +87,6 @@ func TestMemoryClose(t *testing.T) {
8887
mm, err := mustMmapableArray(t, 0).Memory()
8988
qt.Assert(t, qt.IsNil(err))
9089

91-
// Avoid unmap running twice.
92-
runtime.SetFinalizer(mm, nil)
93-
9490
// unmap panics if the operation fails.
9591
mm.close()
9692
}

memory_unsafe.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func newUnsafeMemory(fd, size int) (*Memory, error) {
8787
unsafe.Slice((*byte)(alloc), size),
8888
ro,
8989
true,
90+
runtime.Cleanup{},
9091
}
9192

9293
return mm, nil

perf/ring.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type perfEventRing struct {
2222
cpu int
2323
mmap []byte
2424
ringReader
25+
cleanup runtime.Cleanup
2526
}
2627

2728
func newPerfEventRing(cpu, perCPUBuffer int, opts ReaderOptions) (_ *sys.FD, _ *perfEventRing, err error) {
@@ -73,7 +74,9 @@ func newPerfEventRing(cpu, perCPUBuffer int, opts ReaderOptions) (_ *sys.FD, _ *
7374
mmap: mmap,
7475
ringReader: reader,
7576
}
76-
runtime.SetFinalizer(ring, (*perfEventRing).Close)
77+
ring.cleanup = runtime.AddCleanup(ring, func(mmap []byte) {
78+
_ = unix.Munmap(mmap)
79+
}, ring.mmap)
7780

7881
return fd, ring, nil
7982
}
@@ -95,7 +98,7 @@ func perfBufferSize(perCPUBuffer int) int {
9598
}
9699

97100
func (ring *perfEventRing) Close() error {
98-
runtime.SetFinalizer(ring, nil)
101+
ring.cleanup.Stop()
99102
mmap := ring.mmap
100103
ring.mmap = nil
101104
return unix.Munmap(mmap)

0 commit comments

Comments
 (0)