Source file
src/syscall/syscall_linux_test.go
1
2
3
4
5 package syscall_test
6
7 import (
8 "fmt"
9 "internal/testenv"
10 "io"
11 "io/fs"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "runtime"
16 "slices"
17 "strconv"
18 "strings"
19 "sync"
20 "syscall"
21 "testing"
22 "unsafe"
23 )
24
25
26
27 func chtmpdir(t *testing.T) func() {
28 oldwd, err := os.Getwd()
29 if err != nil {
30 t.Fatalf("chtmpdir: %v", err)
31 }
32 d, err := os.MkdirTemp("", "test")
33 if err != nil {
34 t.Fatalf("chtmpdir: %v", err)
35 }
36 if err := os.Chdir(d); err != nil {
37 t.Fatalf("chtmpdir: %v", err)
38 }
39 return func() {
40 if err := os.Chdir(oldwd); err != nil {
41 t.Fatalf("chtmpdir: %v", err)
42 }
43 os.RemoveAll(d)
44 }
45 }
46
47 func touch(t *testing.T, name string) {
48 f, err := os.Create(name)
49 if err != nil {
50 t.Fatal(err)
51 }
52 if err := f.Close(); err != nil {
53 t.Fatal(err)
54 }
55 }
56
57 const (
58 _AT_SYMLINK_NOFOLLOW = 0x100
59 _AT_FDCWD = -0x64
60 _AT_EACCESS = 0x200
61 _F_OK = 0
62 _R_OK = 4
63 )
64
65 func TestFaccessat(t *testing.T) {
66 defer chtmpdir(t)()
67 touch(t, "file1")
68
69 err := syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, 0)
70 if err != nil {
71 t.Errorf("Faccessat: unexpected error: %v", err)
72 }
73
74 err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, 2)
75 if err != syscall.EINVAL {
76 t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err)
77 }
78
79 err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, _AT_EACCESS)
80 if err != nil {
81 t.Errorf("Faccessat: unexpected error: %v", err)
82 }
83
84 err = os.Symlink("file1", "symlink1")
85 if err != nil {
86 t.Fatal(err)
87 }
88
89 err = syscall.Faccessat(_AT_FDCWD, "symlink1", _R_OK, _AT_SYMLINK_NOFOLLOW)
90 if err != nil {
91 t.Errorf("Faccessat SYMLINK_NOFOLLOW: unexpected error %v", err)
92 }
93
94
95
96
97
98
99 err = syscall.Fchmodat(_AT_FDCWD, "file1", 0, 0)
100 if err != nil {
101 t.Errorf("Fchmodat: unexpected error %v", err)
102 }
103
104 err = syscall.Faccessat(_AT_FDCWD, "file1", _F_OK, _AT_SYMLINK_NOFOLLOW)
105 if err != nil {
106 t.Errorf("Faccessat: unexpected error: %v", err)
107 }
108
109 err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, _AT_SYMLINK_NOFOLLOW)
110 if err != syscall.EACCES {
111 if syscall.Getuid() != 0 {
112 t.Errorf("Faccessat: unexpected error: %v, want EACCES", err)
113 }
114 }
115 }
116
117 func TestFchmodat(t *testing.T) {
118 defer chtmpdir(t)()
119
120 touch(t, "file1")
121 os.Symlink("file1", "symlink1")
122
123 err := syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, 0)
124 if err != nil {
125 t.Fatalf("Fchmodat: unexpected error: %v", err)
126 }
127
128 fi, err := os.Stat("file1")
129 if err != nil {
130 t.Fatal(err)
131 }
132
133 if fi.Mode() != 0444 {
134 t.Errorf("Fchmodat: failed to change mode: expected %v, got %v", 0444, fi.Mode())
135 }
136
137 err = syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, _AT_SYMLINK_NOFOLLOW)
138 if err != syscall.EOPNOTSUPP {
139 t.Fatalf("Fchmodat: unexpected error: %v, expected EOPNOTSUPP", err)
140 }
141 }
142
143 func TestMain(m *testing.M) {
144 if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
145 deathSignalParent()
146 } else if os.Getenv("GO_DEATHSIG_CHILD") == "1" {
147 deathSignalChild()
148 } else if os.Getenv("GO_SYSCALL_NOERROR") == "1" {
149 syscallNoError()
150 }
151
152 os.Exit(m.Run())
153 }
154
155 func TestParseNetlinkMessage(t *testing.T) {
156 for i, b := range [][]byte{
157 {103, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 5, 8, 0, 3,
158 0, 8, 0, 6, 0, 0, 0, 0, 1, 63, 0, 10, 0, 69, 16, 0, 59, 39, 82, 64, 0, 64, 6, 21, 89, 127, 0, 0,
159 1, 127, 0, 0, 1, 230, 228, 31, 144, 32, 186, 155, 211, 185, 151, 209, 179, 128, 24, 1, 86,
160 53, 119, 0, 0, 1, 1, 8, 10, 0, 17, 234, 12, 0, 17, 189, 126, 107, 106, 108, 107, 106, 13, 10,
161 },
162 {106, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 3, 8, 0, 3,
163 0, 8, 0, 6, 0, 0, 0, 0, 1, 66, 0, 10, 0, 69, 0, 0, 62, 230, 255, 64, 0, 64, 6, 85, 184, 127, 0, 0,
164 1, 127, 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 65, 250, 60, 192, 97, 128, 24, 1, 86, 253, 21, 0,
165 0, 1, 1, 8, 10, 0, 51, 106, 89, 0, 51, 102, 198, 108, 104, 106, 108, 107, 104, 108, 107, 104, 10,
166 },
167 {102, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 1, 8, 0, 3, 0,
168 8, 0, 6, 0, 0, 0, 0, 1, 62, 0, 10, 0, 69, 0, 0, 58, 231, 2, 64, 0, 64, 6, 85, 185, 127, 0, 0, 1, 127,
169 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 86, 250, 60, 192, 97, 128, 24, 1, 86, 104, 64, 0, 0, 1, 1, 8,
170 10, 0, 52, 198, 200, 0, 51, 135, 232, 101, 115, 97, 103, 103, 10,
171 },
172 } {
173 m, err := syscall.ParseNetlinkMessage(b)
174 if err != syscall.EINVAL {
175 t.Errorf("#%d: got %v; want EINVAL", i, err)
176 }
177 if m != nil {
178 t.Errorf("#%d: got %v; want nil", i, m)
179 }
180 }
181 }
182
183 func TestSyscallNoError(t *testing.T) {
184
185
186
187 if unsafe.Sizeof(uintptr(0)) != 4 {
188 t.Skip("skipping on non-32bit architecture")
189 }
190
191
192
193
194
195 if runtime.GOARCH == "mips" || runtime.GOARCH == "mipsle" {
196 t.Skipf("skipping on %s", runtime.GOARCH)
197 }
198
199 if os.Getuid() != 0 {
200 t.Skip("skipping root only test")
201 }
202 if testing.Short() && testenv.Builder() != "" && os.Getenv("USER") == "swarming" {
203
204
205
206
207 t.Skip("skipping root only test on a non-root builder")
208 }
209
210 if runtime.GOOS == "android" {
211 t.Skip("skipping on rooted android, see issue 27364")
212 }
213
214
215
216 tempDir, err := os.MkdirTemp("", "TestSyscallNoError")
217 if err != nil {
218 t.Fatalf("cannot create temporary directory: %v", err)
219 }
220 defer os.RemoveAll(tempDir)
221 os.Chmod(tempDir, 0755)
222
223 tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
224
225 src, err := os.Open(os.Args[0])
226 if err != nil {
227 t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
228 }
229 defer src.Close()
230
231 dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
232 if err != nil {
233 t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
234 }
235 if _, err := io.Copy(dst, src); err != nil {
236 t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
237 }
238 err = dst.Close()
239 if err != nil {
240 t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
241 }
242
243 uid := uint32(0xfffffffe)
244 err = os.Chown(tmpBinary, int(uid), -1)
245 if err != nil {
246 t.Fatalf("failed to chown test binary %q, %v", tmpBinary, err)
247 }
248
249 err = os.Chmod(tmpBinary, 0755|fs.ModeSetuid)
250 if err != nil {
251 t.Fatalf("failed to set setuid bit on test binary %q, %v", tmpBinary, err)
252 }
253
254 cmd := exec.Command(tmpBinary)
255 cmd.Env = append(os.Environ(), "GO_SYSCALL_NOERROR=1")
256
257 out, err := cmd.CombinedOutput()
258 if err != nil {
259 t.Fatalf("failed to start first child process: %v", err)
260 }
261
262 got := strings.TrimSpace(string(out))
263 want := strconv.FormatUint(uint64(uid)+1, 10) + " / " +
264 strconv.FormatUint(uint64(-uid), 10) + " / " +
265 strconv.FormatUint(uint64(uid), 10)
266 if got != want {
267 if filesystemIsNoSUID(tmpBinary) {
268 t.Skip("skipping test when temp dir is mounted nosuid")
269 }
270
271 t.Errorf("expected %s,\ngot %s", want, got)
272 }
273 }
274
275
276
277 func filesystemIsNoSUID(path string) bool {
278 var st syscall.Statfs_t
279 if syscall.Statfs(path, &st) != nil {
280 return false
281 }
282 return st.Flags&syscall.MS_NOSUID != 0
283 }
284
285 func syscallNoError() {
286
287
288 euid1, _, e := syscall.RawSyscall(syscall.Sys_GETEUID, 0, 0, 0)
289 euid2, _ := syscall.RawSyscallNoError(syscall.Sys_GETEUID, 0, 0, 0)
290
291 fmt.Println(uintptr(euid1), "/", int(e), "/", uintptr(euid2))
292 os.Exit(0)
293 }
294
295
296 const (
297 PR_GET_KEEPCAPS uintptr = 7
298 PR_SET_KEEPCAPS = 8
299 )
300
301
302
303
304 func TestAllThreadsSyscall(t *testing.T) {
305 if _, _, err := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, 0, 0); err == syscall.ENOTSUP {
306 t.Skip("AllThreadsSyscall disabled with cgo")
307 }
308
309 fns := []struct {
310 label string
311 fn func(uintptr) error
312 }{
313 {
314 label: "prctl<3-args>",
315 fn: func(v uintptr) error {
316 _, _, e := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, v, 0)
317 if e != 0 {
318 return e
319 }
320 return nil
321 },
322 },
323 {
324 label: "prctl<6-args>",
325 fn: func(v uintptr) error {
326 _, _, e := syscall.AllThreadsSyscall6(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, v, 0, 0, 0, 0)
327 if e != 0 {
328 return e
329 }
330 return nil
331 },
332 },
333 }
334
335 waiter := func(q <-chan uintptr, r chan<- uintptr, once bool) {
336 for x := range q {
337 runtime.LockOSThread()
338 v, _, e := syscall.Syscall(syscall.SYS_PRCTL, PR_GET_KEEPCAPS, 0, 0)
339 if e != 0 {
340 t.Errorf("tid=%d prctl(PR_GET_KEEPCAPS) failed: %v", syscall.Gettid(), e)
341 } else if x != v {
342 t.Errorf("tid=%d prctl(PR_GET_KEEPCAPS) mismatch: got=%d want=%d", syscall.Gettid(), v, x)
343 }
344 r <- v
345 if once {
346 break
347 }
348 runtime.UnlockOSThread()
349 }
350 }
351
352
353 const launches = 11
354 question := make(chan uintptr)
355 response := make(chan uintptr)
356 defer close(question)
357
358 routines := 0
359 for i, v := range fns {
360 for j := 0; j < launches; j++ {
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375 once := routines%5 == 4
376 go waiter(question, response, once)
377
378
379
380
381
382
383
384 routines++
385
386
387
388
389
390 want := uintptr(j & 1)
391
392
393 if err := v.fn(want); err != nil {
394 t.Errorf("[%d,%d] %s(PR_SET_KEEPCAPS, %d, ...): %v", i, j, v.label, j&1, err)
395 }
396
397
398
399
400 for k := 0; k < routines; k++ {
401 question <- want
402 }
403
404
405
406
407 for k := 0; k < routines; k++ {
408 if got := <-response; got != want {
409 t.Errorf("[%d,%d,%d] waiter result got=%d, want=%d", i, j, k, got, want)
410 }
411 }
412
413
414
415 runtime.Gosched()
416
417 if once {
418
419 routines--
420 }
421
422
423
424 if v, _, e := syscall.Syscall(syscall.SYS_PRCTL, PR_GET_KEEPCAPS, 0, 0); e != 0 {
425 t.Errorf("[%d,%d] prctl(PR_GET_KEEPCAPS) failed: %v", i, j, e)
426 } else if v != want {
427 t.Errorf("[%d,%d] prctl(PR_GET_KEEPCAPS) gave wrong value: got=%v, want=1", i, j, v)
428 }
429 }
430 }
431 }
432
433
434
435 func compareStatus(filter, expect string) error {
436 expected := filter + expect
437 pid := syscall.Getpid()
438 fs, err := os.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
439 if err != nil {
440 return fmt.Errorf("unable to find %d tasks: %v", pid, err)
441 }
442 expectedProc := fmt.Sprintf("Pid:\t%d", pid)
443 foundAThread := false
444 for _, f := range fs {
445 tf := fmt.Sprintf("/proc/%s/status", f.Name())
446 d, err := os.ReadFile(tf)
447 if err != nil {
448
449
450
451
452
453
454
455 continue
456 }
457 lines := strings.Split(string(d), "\n")
458 for _, line := range lines {
459
460 line = strings.TrimSpace(line)
461 if strings.HasPrefix(line, "Pid:\t") {
462
463
464
465
466
467
468
469
470
471 if line != expectedProc {
472 break
473 }
474
475
476
477 }
478 if strings.HasPrefix(line, filter) {
479 if line == expected {
480 foundAThread = true
481 break
482 }
483 if filter == "Groups:" && strings.HasPrefix(line, "Groups:\t") {
484
485
486 a := strings.Split(line[8:], " ")
487 slices.Sort(a)
488 got := strings.Join(a, " ")
489 if got == expected[8:] {
490 foundAThread = true
491 break
492 }
493
494 }
495 return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc)
496 }
497 }
498 }
499 if !foundAThread {
500 return fmt.Errorf("found no thread /proc/<TID>/status files for process %q", expectedProc)
501 }
502 return nil
503 }
504
505
506
507 func killAThread(c <-chan struct{}) {
508 runtime.LockOSThread()
509 <-c
510 return
511 }
512
513
514
515
516
517
518
519
520
521
522
523 func TestSetuidEtc(t *testing.T) {
524 if syscall.Getuid() != 0 {
525 t.Skip("skipping root only test")
526 }
527 if testing.Short() && testenv.Builder() != "" && os.Getenv("USER") == "swarming" {
528
529
530
531
532 t.Skip("skipping root only test on a non-root builder")
533 }
534 if _, err := os.Stat("/etc/alpine-release"); err == nil {
535 t.Skip("skipping glibc test on alpine - go.dev/issue/19938")
536 }
537 vs := []struct {
538 call string
539 fn func() error
540 filter, expect string
541 }{
542 {call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "\t0\t1\t0\t1"},
543 {call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
544
545 {call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "\t0\t1\t0\t1"},
546 {call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
547
548 {call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "\t1\t1\t1\t1"},
549 {call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
550
551 {call: "Setgroups([]int{0,1,2,3})", fn: func() error { return syscall.Setgroups([]int{0, 1, 2, 3}) }, filter: "Groups:", expect: "\t0 1 2 3"},
552 {call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: ""},
553 {call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "\t0"},
554
555 {call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "\t101\t0\t0\t0"},
556 {call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "\t0\t102\t102\t102"},
557 {call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
558
559 {call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "\t1\t0\t0\t0"},
560 {call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "\t0\t2\t2\t2"},
561 {call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
562
563 {call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "\t101\t0\t102\t0"},
564 {call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "\t0\t102\t101\t102"},
565 {call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
566
567 {call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "\t1\t0\t2\t0"},
568 {call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "\t0\t2\t1\t2"},
569 {call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
570 }
571
572 for i, v := range vs {
573
574 c := make(chan struct{})
575 go killAThread(c)
576 close(c)
577
578 if err := v.fn(); err != nil {
579 t.Errorf("[%d] %q failed: %v", i, v.call, err)
580 continue
581 }
582 if err := compareStatus(v.filter, v.expect); err != nil {
583 t.Errorf("[%d] %q comparison: %v", i, v.call, err)
584 }
585 }
586 }
587
588
589
590 func TestAllThreadsSyscallError(t *testing.T) {
591
592
593 r1, r2, err := syscall.AllThreadsSyscall(syscall.SYS_CAPGET, 0, 0, 0)
594 if err == syscall.ENOTSUP {
595 t.Skip("AllThreadsSyscall disabled with cgo")
596 }
597 if err != syscall.EFAULT {
598 t.Errorf("AllThreadSyscall(SYS_CAPGET) got %d, %d, %v, want err %v", r1, r2, err, syscall.EFAULT)
599 }
600 }
601
602
603
604
605 func TestAllThreadsSyscallBlockedSyscall(t *testing.T) {
606 if _, _, err := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, 0, 0); err == syscall.ENOTSUP {
607 t.Skip("AllThreadsSyscall disabled with cgo")
608 }
609
610 rd, wr, err := os.Pipe()
611 if err != nil {
612 t.Fatalf("unable to obtain a pipe: %v", err)
613 }
614
615
616 var wg sync.WaitGroup
617 ready := make(chan bool)
618 wg.Add(1)
619 go func() {
620 data := make([]byte, 1)
621
622
623
624
625 ready <- true
626
627
628
629 n, err := syscall.Read(int(rd.Fd()), data)
630 if !(n == 0 && err == nil) {
631 t.Errorf("expected read to return 0, got %d, %s", n, err)
632 }
633
634
635
636 rd.Close()
637 wg.Done()
638 }()
639 <-ready
640
641
642
643 pid := syscall.Getpid()
644 for i := 0; i < 100; i++ {
645 if id, _, e := syscall.AllThreadsSyscall(syscall.SYS_GETPID, 0, 0, 0); e != 0 {
646 t.Errorf("[%d] getpid failed: %v", i, e)
647 } else if int(id) != pid {
648 t.Errorf("[%d] getpid got=%d, want=%d", i, id, pid)
649 }
650
651
652 runtime.Gosched()
653 }
654 wr.Close()
655 wg.Wait()
656 }
657
658 func TestPrlimitSelf(t *testing.T) {
659 origLimit := syscall.OrigRlimitNofile()
660 origRlimitNofile := syscall.GetInternalOrigRlimitNofile()
661
662 if origLimit == nil {
663 defer origRlimitNofile.Store(origLimit)
664 origRlimitNofile.Store(&syscall.Rlimit{
665 Cur: 1024,
666 Max: 65536,
667 })
668 }
669
670
671 var lim syscall.Rlimit
672 if err := syscall.Prlimit(0, syscall.RLIMIT_NOFILE, nil, &lim); err != nil {
673 t.Fatalf("Failed to get the current nofile limit: %v", err)
674 }
675
676 if err := syscall.Prlimit(0, syscall.RLIMIT_NOFILE, &lim, nil); err != nil {
677 t.Fatalf("Prlimit self failed: %v", err)
678 }
679
680 rlimLater := origRlimitNofile.Load()
681 if rlimLater != nil {
682 t.Fatalf("origRlimitNofile got=%v, want=nil", rlimLater)
683 }
684 }
685
686 func TestPrlimitOtherProcess(t *testing.T) {
687 origLimit := syscall.OrigRlimitNofile()
688 origRlimitNofile := syscall.GetInternalOrigRlimitNofile()
689
690 if origLimit == nil {
691 defer origRlimitNofile.Store(origLimit)
692 origRlimitNofile.Store(&syscall.Rlimit{
693 Cur: 1024,
694 Max: 65536,
695 })
696 }
697 rlimOrig := origRlimitNofile.Load()
698
699
700
701 cmd := exec.Command("sleep", "infinity")
702 cmd.Start()
703 defer func() {
704 cmd.Process.Kill()
705 cmd.Process.Wait()
706 }()
707
708
709 var lim syscall.Rlimit
710 if err := syscall.Prlimit(cmd.Process.Pid, syscall.RLIMIT_NOFILE, nil, &lim); err != nil {
711 t.Fatalf("Failed to get the current nofile limit: %v", err)
712 }
713
714 if err := syscall.Prlimit(cmd.Process.Pid, syscall.RLIMIT_NOFILE, &lim, nil); err != nil {
715 t.Fatalf("Prlimit(%d) failed: %v", cmd.Process.Pid, err)
716 }
717
718 rlimLater := origRlimitNofile.Load()
719 if rlimLater != rlimOrig {
720 t.Fatalf("origRlimitNofile got=%v, want=%v", rlimLater, rlimOrig)
721 }
722 }
723
View as plain text