diff options
-rw-r--r-- | CHANGELOG.md | 7 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/sys/ptrace/linux.rs | 47 | ||||
-rw-r--r-- | src/sys/time.rs | 26 | ||||
-rw-r--r-- | src/time.rs | 258 | ||||
-rw-r--r-- | src/unistd.rs | 6 | ||||
-rw-r--r-- | test/sys/test_ptrace.rs | 4 | ||||
-rw-r--r-- | test/sys/test_uio.rs | 2 | ||||
-rw-r--r-- | test/sys/test_wait.rs | 8 | ||||
-rw-r--r-- | test/test.rs | 1 | ||||
-rw-r--r-- | test/test_time.rs | 56 | ||||
-rw-r--r-- | test/test_unistd.rs | 6 |
12 files changed, 408 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 061d1b9f..50d442d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Added Netlink protocol families to the `SockProtocol` enum (#[1289](https://github.com/nix-rust/nix/pull/1289)) +- Added `clock_gettime`, `clock_settime`, `clock_getres`, + `clock_getcpuclockid` functions and `ClockId` struct. + (#[1281](https://github.com/nix-rust/nix/pull/1281)) +- Added wrapper functions for `PTRACE_SYSEMU` and `PTRACE_SYSEMU_SINGLESTEP`. + (#[1300](https://github.com/nix-rust/nix/pull/1300)) ### Changed - Expose `SeekData` and `SeekHole` on all Linux targets (#[1284](https://github.com/nix-rust/nix/pull/1284)) - Changed unistd::{execv,execve,execvp,execvpe,fexecve,execveat} to take both `&[&CStr]` and `&[CString]` as its list argument(s). (#[1278](https://github.com/nix-rust/nix/pull/1278)) +- Made `unistd::fork` an unsafe funtion, bringing it in line with [libstd's decision](https://github.com/rust-lang/rust/pull/58059). + (#[1293](https://github.com/nix-rust/nix/pull/1293)) ### Fixed ### Removed @@ -61,6 +61,7 @@ pub mod poll; pub mod pty; pub mod sched; pub mod sys; +pub mod time; // This can be implemented for other platforms as soon as libc // provides bindings for them. #[cfg(all(target_os = "linux", diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index a0bae14f..8d1dd16e 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -109,6 +109,12 @@ libc_enum!{ #[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))] PTRACE_PEEKSIGINFO, + #[cfg(all(target_os = "linux", target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64")))] + PTRACE_SYSEMU, + #[cfg(all(target_os = "linux", target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64")))] + PTRACE_SYSEMU_SINGLESTEP, } } @@ -278,7 +284,7 @@ pub fn traceme() -> Result<()> { } } -/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` +/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` /// /// Arranges for the tracee to be stopped at the next entry to or exit from a system call, /// optionally delivering a signal specified by `sig`. @@ -297,6 +303,23 @@ pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { } } +/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)` +/// +/// In contrast to the `syscall` function, the syscall stopped at will not be executed. +/// Thus the the tracee will only be stopped once per syscall, +/// optionally delivering a signal specified by `sig`. +#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] +pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop) + // ignore the useless return value + } +} + /// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` /// /// Attaches to the process specified by `pid`, making it a tracee of the calling process. @@ -402,6 +425,28 @@ pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { } } +/// Move the stopped tracee process forward by a single step or stop at the next syscall +/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)` +/// +/// Advances the execution by a single step or until the next syscall. +/// In case the tracee is stopped at a syscall, the syscall will not be executed. +/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. +#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] +pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other( + Request::PTRACE_SYSEMU_SINGLESTEP, + pid, + ptr::null_mut(), + data, + ) + .map(drop) // ignore the useless return value + } +} /// Reads a word from a processes memory at the given address pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> { diff --git a/src/sys/time.rs b/src/sys/time.rs index 973a3526..269b4253 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -1,4 +1,5 @@ use std::{cmp, fmt, ops}; +use std::time::Duration; use std::convert::From; use libc::{c_long, timespec, timeval}; pub use libc::{time_t, suseconds_t}; @@ -66,6 +67,21 @@ impl From<timespec> for TimeSpec { } } +impl From<Duration> for TimeSpec { + fn from(duration: Duration) -> Self { + TimeSpec(timespec { + tv_sec: duration.as_secs() as time_t, + tv_nsec: duration.subsec_nanos() as c_long + }) + } +} + +impl From<TimeSpec> for Duration { + fn from(timespec: TimeSpec) -> Self { + Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32) + } +} + impl AsRef<timespec> for TimeSpec { fn as_ref(&self) -> ×pec { &self.0 @@ -484,6 +500,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { #[cfg(test)] mod test { use super::{TimeSpec, TimeVal, TimeValLike}; + use std::time::Duration; #[test] pub fn test_timespec() { @@ -495,6 +512,15 @@ mod test { } #[test] + pub fn test_timespec_from() { + let duration = Duration::new(123, 123_456_789); + let timespec = TimeSpec::nanoseconds(123_123_456_789); + + assert_eq!(TimeSpec::from(duration), timespec); + assert_eq!(Duration::from(timespec), duration); + } + + #[test] pub fn test_timespec_neg() { let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 00000000..54989c2e --- /dev/null +++ b/src/time.rs @@ -0,0 +1,258 @@ +use crate::sys::time::TimeSpec; +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +use crate::{unistd::Pid, Error}; +use crate::{Errno, Result}; +use libc::{self, clockid_t}; +use std::mem::MaybeUninit; + +/// Clock identifier +/// +/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by +/// accidentally passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ClockId(clockid_t); + +impl ClockId { + /// Creates `ClockId` from raw `clockid_t` + pub fn from_raw(clk_id: clockid_t) -> Self { + ClockId(clk_id) + } + + /// Returns `ClockId` of a `pid` CPU-time clock + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + ))] + pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> { + clock_getcpuclockid(pid) + } + + /// Returns resolution of the clock id + pub fn res(self) -> Result<TimeSpec> { + clock_getres(self) + } + + /// Returns the current time on the clock id + pub fn now(self) -> Result<TimeSpec> { + clock_gettime(self) + } + + /// Sets time to `timespec` on the clock id + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + all( + not(any(target_env = "uclibc", target_env = "newlibc")), + any(target_os = "redox", target_os = "hermit",), + ), + )))] + pub fn set_time(self, timespec: TimeSpec) -> Result<()> { + clock_settime(self, timespec) + } + + /// Gets the raw `clockid_t` wrapped by `self` + pub fn as_raw(self) -> clockid_t { + self.0 + } + + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + ) + ))] + pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "linux", target_os = "android", target_os = "emscripten") + ) + ))] + pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); + pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "linux", target_os = "android", target_os = "emscripten") + ) + ))] + pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "linux", target_os = "android", target_os = "emscripten") + ) + ))] + pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); + #[cfg(any( + target_os = "fuchsia", + target_env = "uclibc", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + all( + not(target_env = "newlib"), + any(target_os = "linux", target_os = "android", target_os = "emscripten") + ) + ))] + pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); + pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "linux", target_os = "android", target_os = "emscripten") + ) + ))] + pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "linux", target_os = "android", target_os = "emscripten") + ) + ))] + pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any( + target_os = "emscripten", + all(target_os = "linux", target_env = "musl") + ) + ) + ))] + pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); + #[cfg(any( + target_os = "fuchsia", + all( + not(any(target_env = "uclibc", target_env = "newlib")), + any( + target_os = "emscripten", + all(target_os = "linux", target_env = "musl") + ) + ) + ))] + pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); + #[cfg(any( + target_env = "uclibc", + target_os = "fuchsia", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + all( + not(target_env = "newlib"), + any(target_os = "linux", target_os = "android", target_os = "emscripten",), + ), + ))] + pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE); + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); +} + +impl Into<clockid_t> for ClockId { + fn into(self) -> clockid_t { + self.as_raw() + } +} + +impl From<clockid_t> for ClockId { + fn from(clk_id: clockid_t) -> Self { + ClockId::from_raw(clk_id) + } +} + +impl std::fmt::Display for ClockId { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} + +/// Get the resolution of the specified clock, (see +/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)). +pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> { + let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); + let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; + Errno::result(ret)?; + let res = unsafe { c_time.assume_init() }; + Ok(TimeSpec::from(res)) +} + +/// Get the time of the specified clock, (see +/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)). +pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> { + let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit(); + let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; + Errno::result(ret)?; + let res = unsafe { c_time.assume_init() }; + Ok(TimeSpec::from(res)) +} + +/// Set the time of the specified clock, (see +/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)). +#[cfg(not(any( + target_os = "macos", + target_os = "ios", + all( + not(any(target_env = "uclibc", target_env = "newlibc")), + any(target_os = "redox", target_os = "hermit",), + ), +)))] +pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { + let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; + Errno::result(ret).map(drop) +} + +/// Get the clock id of the specified process id, (see +/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)). +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> { + let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit(); + let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; + if ret == 0 { + let res = unsafe { clk_id.assume_init() }; + Ok(ClockId::from(res)) + } else { + Err(Error::Sys(Errno::from_i32(ret))) + } +} diff --git a/src/unistd.rs b/src/unistd.rs index 4a7903a3..04031e37 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -200,7 +200,7 @@ impl ForkResult { /// ```no_run /// use nix::unistd::{fork, ForkResult}; /// -/// match fork() { +/// match unsafe{fork()} { /// Ok(ForkResult::Parent { child, .. }) => { /// println!("Continuing execution in parent process, new child has pid: {}", child); /// } @@ -230,9 +230,9 @@ impl ForkResult { /// /// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html #[inline] -pub fn fork() -> Result<ForkResult> { +pub unsafe fn fork() -> Result<ForkResult> { use self::ForkResult::*; - let res = unsafe { libc::fork() }; + let res = libc::fork(); Errno::result(res).map(|res| match res { 0 => Child, diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 46ea3d6a..3b60dd70 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -81,7 +81,7 @@ fn test_ptrace_cont() { return; } - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Child => { ptrace::traceme().unwrap(); // As recommended by ptrace(2), raise SIGTRAP to pause the child @@ -132,7 +132,7 @@ fn test_ptrace_syscall() { let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Child => { ptrace::traceme().unwrap(); // first sigstop until parent is ready to continue diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 236560f4..4fa838c9 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -212,7 +212,7 @@ fn test_process_vm_readv() { let mut vector = vec![1u8, 2, 3, 4, 5]; let (r, w) = pipe().unwrap(); - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Parent { child } => { close(w).unwrap(); // wait for child diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index 53b7c84a..d1056250 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -11,7 +11,7 @@ fn test_wait_signal() { let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Child => { pause(); unsafe { _exit(123) } @@ -28,7 +28,7 @@ fn test_wait_exit() { let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: Child only calls `_exit`, which is async-signal-safe. - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Child => unsafe { _exit(12); }, Parent { child } => { assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12))); @@ -48,7 +48,7 @@ fn test_waitstatus_from_raw() { fn test_waitstatus_pid() { let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); - match fork().unwrap() { + match unsafe{fork()}.unwrap() { Child => unsafe { _exit(0) }, Parent { child } => { let status = waitpid(child, None).unwrap(); @@ -98,7 +98,7 @@ mod ptrace { require_capability!(CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Child => ptrace_child(), Parent { child } => ptrace_parent(child), } diff --git a/test/test.rs b/test/test.rs index 2d43196c..8ad09b6a 100644 --- a/test/test.rs +++ b/test/test.rs @@ -139,6 +139,7 @@ mod test_sched; target_os = "macos"))] mod test_sendfile; mod test_stat; +mod test_time; mod test_unistd; use std::os::unix::io::RawFd; diff --git a/test/test_time.rs b/test/test_time.rs new file mode 100644 index 00000000..c321352d --- /dev/null +++ b/test/test_time.rs @@ -0,0 +1,56 @@ +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +use nix::time::clock_getcpuclockid; +use nix::time::{clock_getres, clock_gettime, ClockId}; + +#[test] +pub fn test_clock_getres() { + assert!(clock_getres(ClockId::CLOCK_REALTIME).is_ok()); +} + +#[test] +pub fn test_clock_gettime() { + assert!(clock_gettime(ClockId::CLOCK_REALTIME).is_ok()); +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +#[test] +pub fn test_clock_getcpuclockid() { + let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); + assert!(clock_gettime(clock_id).is_ok()); +} + +#[test] +pub fn test_clock_id_res() { + assert!(ClockId::CLOCK_REALTIME.res().is_ok()); +} + +#[test] +pub fn test_clock_id_now() { + assert!(ClockId::CLOCK_REALTIME.now().is_ok()); +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "emscripten", +))] +#[test] +pub fn test_clock_id_pid_cpu_clock_id() { + assert!(ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) + .map(ClockId::now) + .is_ok()); +} diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 0b2a810a..c7a75fbe 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -32,7 +32,7 @@ fn test_fork_and_waitpid() { let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: Child only calls `_exit`, which is signal-safe - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Child => unsafe { _exit(0) }, Parent { child } => { // assert that child was created and pid > 0 @@ -60,7 +60,7 @@ fn test_wait() { let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Safe: Child only calls `_exit`, which is signal-safe - match fork().expect("Error: Fork Failed") { + match unsafe{fork()}.expect("Error: Fork Failed") { Child => unsafe { _exit(0) }, Parent { child } => { let wait_status = wait(); @@ -302,7 +302,7 @@ macro_rules! execve_test_factory( // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function. // NOTE: Technically, this makes the macro unsafe to use because you could pass anything. // The tests make sure not to do that, though. - match fork().unwrap() { + match unsafe{fork()}.unwrap() { Child => { // Make `writer` be the stdout of the new process. dup2(writer, 1).unwrap(); |