diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-10 07:55:13 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-10 07:55:13 +0200 |
| commit | 0930b4c51191ec01cabc03779ef296153ed7f08a (patch) | |
| tree | 9c4a1b27340749cfafe8eaa94880e8d60279da50 /internal | |
| parent | d2ebb8cf2c5f0fccdd703cc64b9f8cecfb539bf9 (diff) | |
probemanager: surface cleanup destroy errors (task 417)
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/probemanager/manager.go | 27 | ||||
| -rw-r--r-- | internal/probemanager/manager_test.go | 75 |
2 files changed, 91 insertions, 11 deletions
diff --git a/internal/probemanager/manager.go b/internal/probemanager/manager.go index 7feb407..4c9dcec 100644 --- a/internal/probemanager/manager.go +++ b/internal/probemanager/manager.go @@ -150,13 +150,11 @@ func (m *Manager) Attach(syscall string) error { defer m.mu.Unlock() entry, err = m.entryLocked(syscall) if err != nil { - if enterLink != nil { - _ = enterLink.Destroy() - } - if exitLink != nil { - _ = exitLink.Destroy() - } - return err + return errors.Join( + err, + destroyLink(fmt.Sprintf("cleanup enter %s", syscall), enterLink), + destroyLink(fmt.Sprintf("cleanup exit %s", syscall), exitLink), + ) } if attachErr != nil { @@ -373,14 +371,21 @@ func attachPair(attacher Attacher, enterTP, exitTP string) (Link, Link, error) { exitLink, err := attachOne(attacher, exitTP) if err != nil { - if enterLink != nil { - _ = enterLink.Destroy() - } - return nil, nil, err + return nil, nil, errors.Join(err, destroyLink("cleanup enter link after exit attach failure", enterLink)) } return enterLink, exitLink, nil } +func destroyLink(action string, link Link) error { + if link == nil { + return nil + } + if err := link.Destroy(); err != nil { + return fmt.Errorf("%s: %w", action, err) + } + return nil +} + func attachOne(attacher Attacher, tracepoint string) (Link, error) { if tracepoint == "" { return nil, nil diff --git a/internal/probemanager/manager_test.go b/internal/probemanager/manager_test.go index b000ced..cc0233b 100644 --- a/internal/probemanager/manager_test.go +++ b/internal/probemanager/manager_test.go @@ -2,6 +2,7 @@ package probemanager import ( "errors" + "strings" "testing" ) @@ -19,10 +20,14 @@ type fakeProgram struct { tracepoint string link *fakeLink err error + onAttach func() } func (p *fakeProgram) AttachTracepoint(_, name string) (Link, error) { p.tracepoint = name + if p.onAttach != nil { + p.onAttach() + } if p.err != nil { return nil, p.err } @@ -240,3 +245,73 @@ func TestManagerIsActiveReflectsCurrentState(t *testing.T) { t.Fatalf("expected unknown syscall to be inactive") } } + +func TestAttachReturnsCleanupErrorsWhenManagerClosesMidAttach(t *testing.T) { + enterDestroyErr := errors.New("enter cleanup failed") + exitDestroyErr := errors.New("exit cleanup failed") + enter := &fakeLink{err: enterDestroyErr} + exit := &fakeLink{err: exitDestroyErr} + + attacher := &fakeAttacher{ + programs: map[string]*fakeProgram{ + "handle_sys_enter_close": {link: enter}, + "handle_sys_exit_close": {link: exit}, + }, + errs: map[string]error{}, + } + mgr := NewManager(attacher) + attacher.programs["handle_sys_exit_close"].onAttach = func() { + if err := mgr.Close(); err != nil { + t.Fatalf("Close returned error during attach hook: %v", err) + } + } + mgr.Register("close", TracepointPair{Enter: "sys_enter_close", Exit: "sys_exit_close"}) + + err := mgr.Attach("close") + if err == nil { + t.Fatalf("expected attach error when manager closes mid-attach") + } + if !strings.Contains(err.Error(), "probe manager is closed") { + t.Fatalf("expected close error in attach result, got %v", err) + } + if !errors.Is(err, enterDestroyErr) { + t.Fatalf("expected joined enter cleanup error, got %v", err) + } + if !errors.Is(err, exitDestroyErr) { + t.Fatalf("expected joined exit cleanup error, got %v", err) + } + if enter.destroyed != 1 || exit.destroyed != 1 { + t.Fatalf("expected both cleanup destroys to run once, got enter=%d exit=%d", enter.destroyed, exit.destroyed) + } +} + +func TestAttachPairReturnsCleanupErrorWhenExitAttachFails(t *testing.T) { + enterDestroyErr := errors.New("enter cleanup failed") + exitAttachErr := errors.New("exit attach failed") + enter := &fakeLink{err: enterDestroyErr} + + attacher := &fakeAttacher{ + programs: map[string]*fakeProgram{ + "handle_sys_enter_close": {link: enter}, + "handle_sys_exit_close": {err: exitAttachErr}, + }, + errs: map[string]error{}, + } + + enterLink, exitLink, err := attachPair(attacher, "sys_enter_close", "sys_exit_close") + if err == nil { + t.Fatalf("expected attachPair error") + } + if enterLink != nil || exitLink != nil { + t.Fatalf("expected failed attachPair to return nil links, got enter=%v exit=%v", enterLink, exitLink) + } + if !errors.Is(err, exitAttachErr) { + t.Fatalf("expected exit attach error in result, got %v", err) + } + if !errors.Is(err, enterDestroyErr) { + t.Fatalf("expected enter cleanup error in result, got %v", err) + } + if enter.destroyed != 1 { + t.Fatalf("expected enter link cleanup to run once, got %d", enter.destroyed) + } +} |
