File tree Expand file tree Collapse file tree 2 files changed +37
-4
lines changed Expand file tree Collapse file tree 2 files changed +37
-4
lines changed Original file line number Diff line number Diff line change @@ -45,10 +45,17 @@ impl IntoRawFd for PtyMaster {
45
45
46
46
impl Drop for PtyMaster {
47
47
fn drop ( & mut self ) {
48
- // Errors when closing are ignored because we don't actually know if the file descriptor
49
- // was closed. If we retried, it's possible that descriptor was reallocated in the mean
50
- // time and the wrong file descriptor could be closed.
51
- let _ = :: unistd:: close ( self . 0 ) ;
48
+ // On drop, we ignore errors like EINTR and EIO because there's no clear
49
+ // way to handle them, we can't return anything, and (on FreeBSD at
50
+ // least) the file descriptor is deallocated in these cases. However,
51
+ // we must panic on EBADF, because it is always an error to close an
52
+ // invalid file descriptor. That frequently indicates a double-close
53
+ // condition, which can cause confusing errors for future I/O
54
+ // operations.
55
+ let e = :: unistd:: close ( self . 0 ) ;
56
+ if e == Err ( Error :: Sys ( Errno :: EBADF ) ) {
57
+ panic ! ( "Closing an invalid file descriptor!" ) ;
58
+ } ;
52
59
}
53
60
}
54
61
Original file line number Diff line number Diff line change
1
+ use std:: io:: Write ;
1
2
use std:: path:: Path ;
2
3
use std:: os:: unix:: prelude:: * ;
4
+ use tempfile:: tempfile;
3
5
4
6
use nix:: fcntl:: { O_RDWR , open} ;
5
7
use nix:: pty:: * ;
6
8
use nix:: sys:: stat;
7
9
use nix:: sys:: termios:: * ;
8
10
use nix:: unistd:: { write, close} ;
9
11
12
+ /// Regression test for Issue #659
13
+ /// PtyMaster should panic rather than double close the file descriptor
14
+ #[ test]
15
+ #[ should_panic( expected = "Closing an invalid file descriptor!" ) ]
16
+ fn test_double_close ( ) {
17
+ let m = posix_openpt ( O_RDWR ) . unwrap ( ) ;
18
+ close ( m. as_raw_fd ( ) ) . unwrap ( ) ;
19
+ drop ( m) ; // should panic here
20
+ }
21
+
22
+ /// Regression test for Issue #659
23
+ /// This is the correct way to explicitly close a PtyMaster
24
+ #[ test]
25
+ fn test_explicit_close ( ) {
26
+ let mut f = {
27
+ let m = posix_openpt ( O_RDWR ) . unwrap ( ) ;
28
+ close ( m. into_raw_fd ( ) ) . unwrap ( ) ;
29
+ tempfile ( ) . unwrap ( )
30
+ } ;
31
+ // This should work. But if there's been a double close, then it will
32
+ // return EBADF
33
+ f. write ( b"whatever" ) . unwrap ( ) ;
34
+ }
35
+
10
36
/// Test equivalence of `ptsname` and `ptsname_r`
11
37
#[ test]
12
38
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
You can’t perform that action at this time.
0 commit comments