@@ -21,23 +21,20 @@ import (
21
21
"net/http/httptest"
22
22
"os"
23
23
"os/exec"
24
+ "os/exec/internal/fdtest"
24
25
"path/filepath"
26
+ "reflect"
25
27
"runtime"
26
28
"strconv"
27
29
"strings"
28
30
"testing"
29
31
"time"
30
32
)
31
33
32
- // haveUnexpectedFDs is set at init time to report whether any
33
- // file descriptors were open at program start.
34
+ // haveUnexpectedFDs is set at init time to report whether any file descriptors
35
+ // were open at program start.
34
36
var haveUnexpectedFDs bool
35
37
36
- // unfinalizedFiles holds files that should not be finalized,
37
- // because that would close the associated file descriptor,
38
- // which we don't want to do.
39
- var unfinalizedFiles []* os.File
40
-
41
38
func init () {
42
39
if os .Getenv ("GO_WANT_HELPER_PROCESS" ) == "1" {
43
40
return
@@ -49,21 +46,10 @@ func init() {
49
46
if poll .IsPollDescriptor (fd ) {
50
47
continue
51
48
}
52
- // We have no good portable way to check whether an FD is open.
53
- // We use NewFile to create a *os.File, which lets us
54
- // know whether it is open, but then we have to cope with
55
- // the finalizer on the *os.File.
56
- f := os .NewFile (fd , "" )
57
- if _ , err := f .Stat (); err != nil {
58
- // Close the file to clear the finalizer.
59
- // We expect the Close to fail.
60
- f .Close ()
61
- } else {
62
- fmt .Printf ("fd %d open at test start\n " , fd )
49
+
50
+ if fdtest .Exists (fd ) {
63
51
haveUnexpectedFDs = true
64
- // Use a global variable to avoid running
65
- // the finalizer, which would close the FD.
66
- unfinalizedFiles = append (unfinalizedFiles , f )
52
+ return
67
53
}
68
54
}
69
55
}
@@ -377,50 +363,21 @@ func TestStdinCloseRace(t *testing.T) {
377
363
378
364
// Issue 5071
379
365
func TestPipeLookPathLeak (t * testing.T ) {
380
- // If we are reading from /proc/self/fd we (should) get an exact result.
381
- tolerance := 0
382
-
383
- // Reading /proc/self/fd is more reliable than calling lsof, so try that
384
- // first.
385
- numOpenFDs := func () (int , []byte , error ) {
386
- fds , err := os .ReadDir ("/proc/self/fd" )
387
- if err != nil {
388
- return 0 , nil , err
389
- }
390
- return len (fds ), nil , nil
366
+ if runtime .GOOS == "windows" {
367
+ t .Skip ("we don't currently suppore counting open handles on windows" )
391
368
}
392
- want , before , err := numOpenFDs ()
393
- if err != nil {
394
- // We encountered a problem reading /proc/self/fd (we might be on
395
- // a platform that doesn't have it). Fall back onto lsof.
396
- t .Logf ("using lsof because: %v" , err )
397
- numOpenFDs = func () (int , []byte , error ) {
398
- // Android's stock lsof does not obey the -p option,
399
- // so extra filtering is needed.
400
- // https://golang.org/issue/10206
401
- if runtime .GOOS == "android" {
402
- // numOpenFDsAndroid handles errors itself and
403
- // might skip or fail the test.
404
- n , lsof := numOpenFDsAndroid (t )
405
- return n , lsof , nil
406
- }
407
- lsof , err := exec .Command ("lsof" , "-b" , "-n" , "-p" , strconv .Itoa (os .Getpid ())).Output ()
408
- return bytes .Count (lsof , []byte ("\n " )), lsof , err
409
- }
410
369
411
- // lsof may see file descriptors associated with the fork itself,
412
- // so we allow some extra margin if we have to use it.
413
- // https://golang.org/issue/19243
414
- tolerance = 5
415
-
416
- // Retry reading the number of open file descriptors.
417
- want , before , err = numOpenFDs ()
418
- if err != nil {
419
- t .Log (err )
420
- t .Skipf ("skipping test; error finding or running lsof" )
370
+ openFDs := func () []uintptr {
371
+ var fds []uintptr
372
+ for i := uintptr (0 ); i < 100 ; i ++ {
373
+ if fdtest .Exists (i ) {
374
+ fds = append (fds , i )
375
+ }
421
376
}
377
+ return fds
422
378
}
423
379
380
+ want := openFDs ()
424
381
for i := 0 ; i < 6 ; i ++ {
425
382
cmd := exec .Command ("something-that-does-not-exist-executable" )
426
383
cmd .StdoutPipe ()
@@ -430,59 +387,10 @@ func TestPipeLookPathLeak(t *testing.T) {
430
387
t .Fatal ("unexpected success" )
431
388
}
432
389
}
433
- got , after , err := numOpenFDs ()
434
- if err != nil {
435
- // numOpenFDs has already succeeded once, it should work here.
436
- t .Errorf ("unexpected failure: %v" , err )
437
- }
438
- if got - want > tolerance {
439
- t .Errorf ("number of open file descriptors changed: got %v, want %v" , got , want )
440
- if before != nil {
441
- t .Errorf ("before:\n %v\n " , before )
442
- }
443
- if after != nil {
444
- t .Errorf ("after:\n %v\n " , after )
445
- }
446
- }
447
- }
448
-
449
- func numOpenFDsAndroid (t * testing.T ) (n int , lsof []byte ) {
450
- raw , err := exec .Command ("lsof" ).Output ()
451
- if err != nil {
452
- t .Skip ("skipping test; error finding or running lsof" )
453
- }
454
-
455
- // First find the PID column index by parsing the first line, and
456
- // select lines containing pid in the column.
457
- pid := []byte (strconv .Itoa (os .Getpid ()))
458
- pidCol := - 1
459
-
460
- s := bufio .NewScanner (bytes .NewReader (raw ))
461
- for s .Scan () {
462
- line := s .Bytes ()
463
- fields := bytes .Fields (line )
464
- if pidCol < 0 {
465
- for i , v := range fields {
466
- if bytes .Equal (v , []byte ("PID" )) {
467
- pidCol = i
468
- break
469
- }
470
- }
471
- lsof = append (lsof , line ... )
472
- continue
473
- }
474
- if bytes .Equal (fields [pidCol ], pid ) {
475
- lsof = append (lsof , '\n' )
476
- lsof = append (lsof , line ... )
477
- }
478
- }
479
- if pidCol < 0 {
480
- t .Fatal ("error processing lsof output: unexpected header format" )
481
- }
482
- if err := s .Err (); err != nil {
483
- t .Fatalf ("error processing lsof output: %v" , err )
390
+ got := openFDs ()
391
+ if ! reflect .DeepEqual (got , want ) {
392
+ t .Errorf ("set of open file descriptors changed: got %v, want %v" , got , want )
484
393
}
485
- return bytes .Count (lsof , []byte ("\n " )), lsof
486
394
}
487
395
488
396
func TestExtraFilesFDShuffle (t * testing.T ) {
0 commit comments