1// Copyright 2023 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 5package os_test 6 7import ( 8 "errors" 9 "internal/syscall/unix" 10 "internal/testenv" 11 "os" 12 "os/exec" 13 "syscall" 14 "testing" 15) 16 17func TestFindProcessViaPidfd(t *testing.T) { 18 testenv.MustHaveGoBuild(t) 19 t.Parallel() 20 21 if err := os.CheckPidfdOnce(); err != nil { 22 // Non-pidfd code paths tested in exec_unix_test.go. 23 t.Skipf("skipping: pidfd not available: %v", err) 24 } 25 26 p, err := os.StartProcess(testenv.GoToolPath(t), []string{"go"}, &os.ProcAttr{}) 27 if err != nil { 28 t.Fatalf("starting test process: %v", err) 29 } 30 p.Wait() 31 32 // Use pid of a non-existing process. 33 proc, err := os.FindProcess(p.Pid) 34 // FindProcess should never return errors on Unix. 35 if err != nil { 36 t.Fatalf("FindProcess: got error %v, want <nil>", err) 37 } 38 // FindProcess should never return nil Process. 39 if proc == nil { 40 t.Fatal("FindProcess: got nil, want non-nil") 41 } 42 if proc.Status() != os.StatusDone { 43 t.Fatalf("got process status: %v, want %d", proc.Status(), os.StatusDone) 44 } 45 46 // Check that all Process' public methods work as expected with 47 // "done" Process. 48 if err := proc.Kill(); err != os.ErrProcessDone { 49 t.Errorf("Kill: got %v, want %v", err, os.ErrProcessDone) 50 } 51 if err := proc.Signal(os.Kill); err != os.ErrProcessDone { 52 t.Errorf("Signal: got %v, want %v", err, os.ErrProcessDone) 53 } 54 if _, err := proc.Wait(); !errors.Is(err, syscall.ECHILD) { 55 t.Errorf("Wait: got %v, want %v", err, os.ErrProcessDone) 56 } 57 // Release never returns errors on Unix. 58 if err := proc.Release(); err != nil { 59 t.Fatalf("Release: got %v, want <nil>", err) 60 } 61} 62 63func TestStartProcessWithPidfd(t *testing.T) { 64 testenv.MustHaveGoBuild(t) 65 t.Parallel() 66 67 if err := os.CheckPidfdOnce(); err != nil { 68 // Non-pidfd code paths tested in exec_unix_test.go. 69 t.Skipf("skipping: pidfd not available: %v", err) 70 } 71 72 var pidfd int 73 p, err := os.StartProcess(testenv.GoToolPath(t), []string{"go"}, &os.ProcAttr{ 74 Sys: &syscall.SysProcAttr{ 75 PidFD: &pidfd, 76 }, 77 }) 78 if err != nil { 79 t.Fatalf("starting test process: %v", err) 80 } 81 defer syscall.Close(pidfd) 82 83 if _, err := p.Wait(); err != nil { 84 t.Fatalf("Wait: got %v, want <nil>", err) 85 } 86 87 // Check the pidfd is still valid 88 err = unix.PidFDSendSignal(uintptr(pidfd), syscall.Signal(0)) 89 if !errors.Is(err, syscall.ESRCH) { 90 t.Errorf("SendSignal: got %v, want %v", err, syscall.ESRCH) 91 } 92} 93 94// Issue #69284 95func TestPidfdLeak(t *testing.T) { 96 testenv.MustHaveExec(t) 97 exe, err := os.Executable() 98 if err != nil { 99 t.Fatal(err) 100 } 101 102 // Find the next 10 descriptors. 103 // We need to get more than one descriptor in practice; 104 // the pidfd winds up not being the next descriptor. 105 const count = 10 106 want := make([]int, count) 107 for i := range count { 108 var err error 109 want[i], err = syscall.Open(exe, syscall.O_RDONLY, 0) 110 if err != nil { 111 t.Fatal(err) 112 } 113 } 114 115 // Close the descriptors. 116 for _, d := range want { 117 syscall.Close(d) 118 } 119 120 // Start a process 10 times. 121 for range 10 { 122 // For testing purposes this has to be an absolute path. 123 // Otherwise we will fail finding the executable 124 // and won't start a process at all. 125 cmd := exec.Command("/noSuchExecutable") 126 cmd.Run() 127 } 128 129 // Open the next 10 descriptors again. 130 got := make([]int, count) 131 for i := range count { 132 var err error 133 got[i], err = syscall.Open(exe, syscall.O_RDONLY, 0) 134 if err != nil { 135 t.Fatal(err) 136 } 137 } 138 139 // Close the descriptors 140 for _, d := range got { 141 syscall.Close(d) 142 } 143 144 t.Logf("got %v", got) 145 t.Logf("want %v", want) 146 147 // Allow some slack for runtime epoll descriptors and the like. 148 if got[count-1] > want[count-1]+5 { 149 t.Errorf("got descriptor %d, want %d", got[count-1], want[count-1]) 150 } 151} 152