@@ -17,6 +17,7 @@ use ffi::{OsString, OsStr, CString, CStr};
17
17
use fmt;
18
18
use io:: { self , Error , ErrorKind } ;
19
19
use libc:: { self , pid_t, c_void, c_int, gid_t, uid_t} ;
20
+ use mem;
20
21
use ptr;
21
22
use sys:: fd:: FileDesc ;
22
23
use sys:: fs:: { File , OpenOptions } ;
@@ -313,6 +314,23 @@ impl Process {
313
314
if !envp. is_null ( ) {
314
315
* sys:: os:: environ ( ) = envp as * const _ ;
315
316
}
317
+
318
+ // Reset signal handling so the child process starts in a
319
+ // standardized state. libstd ignores SIGPIPE, and signal-handling
320
+ // libraries often set a mask. Child processes inherit ignored
321
+ // signals and the signal mask from their parent, but most
322
+ // UNIX programs do not reset these things on their own, so we
323
+ // need to clean things up now to avoid confusing the program
324
+ // we're about to run.
325
+ let mut set: c:: sigset_t = mem:: uninitialized ( ) ;
326
+ if c:: sigemptyset ( & mut set) != 0 ||
327
+ c:: pthread_sigmask ( c:: SIG_SETMASK , & set, ptr:: null_mut ( ) ) != 0 ||
328
+ libc:: funcs:: posix01:: signal:: signal (
329
+ libc:: SIGPIPE , mem:: transmute ( c:: SIG_DFL )
330
+ ) == mem:: transmute ( c:: SIG_ERR ) {
331
+ fail ( & mut output) ;
332
+ }
333
+
316
334
let _ = libc:: execvp ( * argv, argv as * mut _ ) ;
317
335
fail ( & mut output)
318
336
}
@@ -418,3 +436,59 @@ fn translate_status(status: c_int) -> ExitStatus {
418
436
ExitStatus :: Signal ( imp:: WTERMSIG ( status) )
419
437
}
420
438
}
439
+
440
+ #[ cfg( test) ]
441
+ mod tests {
442
+ use super :: * ;
443
+ use prelude:: v1:: * ;
444
+
445
+ use ffi:: OsStr ;
446
+ use mem;
447
+ use ptr;
448
+ use libc;
449
+ use sys:: { self , c, cvt, pipe} ;
450
+
451
+ extern {
452
+ fn sigaddset ( set : * mut c:: sigset_t , signum : libc:: c_int ) -> libc:: c_int ;
453
+ }
454
+
455
+ #[ test]
456
+ fn test_process_mask ( ) {
457
+ unsafe {
458
+ // Test to make sure that a signal mask does not get inherited.
459
+ let cmd = Command :: new ( OsStr :: new ( "cat" ) ) ;
460
+ let ( stdin_read, stdin_write) = sys:: pipe:: anon_pipe ( ) . unwrap ( ) ;
461
+ let ( stdout_read, stdout_write) = sys:: pipe:: anon_pipe ( ) . unwrap ( ) ;
462
+
463
+ let mut set: c:: sigset_t = mem:: uninitialized ( ) ;
464
+ let mut old_set: c:: sigset_t = mem:: uninitialized ( ) ;
465
+ cvt ( c:: sigemptyset ( & mut set) ) . unwrap ( ) ;
466
+ cvt ( sigaddset ( & mut set, libc:: SIGINT ) ) . unwrap ( ) ;
467
+ cvt ( c:: pthread_sigmask ( c:: SIG_SETMASK , & set, & mut old_set) ) . unwrap ( ) ;
468
+
469
+ let cat = Process :: spawn ( & cmd, Stdio :: Raw ( stdin_read. raw ( ) ) ,
470
+ Stdio :: Raw ( stdout_write. raw ( ) ) ,
471
+ Stdio :: None ) . unwrap ( ) ;
472
+ drop ( stdin_read) ;
473
+ drop ( stdout_write) ;
474
+
475
+ cvt ( c:: pthread_sigmask ( c:: SIG_SETMASK , & old_set, ptr:: null_mut ( ) ) ) . unwrap ( ) ;
476
+
477
+ cvt ( libc:: funcs:: posix88:: signal:: kill ( cat. id ( ) as libc:: pid_t , libc:: SIGINT ) ) . unwrap ( ) ;
478
+ // We need to wait until SIGINT is definitely delivered. The
479
+ // easiest way is to write something to cat, and try to read it
480
+ // back: if SIGINT is unmasked, it'll get delivered when cat is
481
+ // next scheduled.
482
+ let _ = stdin_write. write ( b"Hello" ) ;
483
+ drop ( stdin_write) ;
484
+
485
+ // Either EOF or failure (EPIPE) is okay.
486
+ let mut buf = [ 0 ; 5 ] ;
487
+ if let Ok ( ret) = stdout_read. read ( & mut buf) {
488
+ assert ! ( ret == 0 ) ;
489
+ }
490
+
491
+ cat. wait ( ) . unwrap ( ) ;
492
+ }
493
+ }
494
+ }
0 commit comments