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