Skip to content

Commit a3136ac

Browse files
committed
mark fork as unsafe
Reasoning: After a fork() in a multithreaded program, only async-signal-safe functions may be called by the child. Calling everything else (including malloc(), mutexes) is undefined behavior.
1 parent d8f3f74 commit a3136ac

File tree

6 files changed

+14
-13
lines changed

6 files changed

+14
-13
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4141
([#1020](https://github.com/nix-rust/nix/pull/1020))
4242
- Replaced `CmsgSpace` with the `cmsg_space` macro.
4343
([#1020](https://github.com/nix-rust/nix/pull/1020))
44-
44+
- Marked `fork` as unsafe function
45+
([#1020](https://github.com/nix-rust/nix/pull/1020))
4546
### Fixed
4647
- Fixed multiple bugs when using `sendmsg` and `recvmsg` with ancillary control messages
4748
([#1020](https://github.com/nix-rust/nix/pull/1020))

src/unistd.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl ForkResult {
192192
/// ```no_run
193193
/// use nix::unistd::{fork, ForkResult};
194194
///
195-
/// match fork() {
195+
/// match unsafe {fork()} {
196196
/// Ok(ForkResult::Parent { child, .. }) => {
197197
/// println!("Continuing execution in parent process, new child has pid: {}", child);
198198
/// }
@@ -222,9 +222,9 @@ impl ForkResult {
222222
///
223223
/// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html
224224
#[inline]
225-
pub fn fork() -> Result<ForkResult> {
225+
pub unsafe fn fork() -> Result<ForkResult> {
226226
use self::ForkResult::*;
227-
let res = unsafe { libc::fork() };
227+
let res = libc::fork();
228228

229229
Errno::result(res).map(|res| match res {
230230
0 => Child,

test/sys/test_ptrace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fn test_ptrace_cont() {
7474
return;
7575
}
7676

77-
match fork().expect("Error: Fork Failed") {
77+
match unsafe {fork()}.expect("Error: Fork Failed") {
7878
Child => {
7979
ptrace::traceme().unwrap();
8080
// As recommended by ptrace(2), raise SIGTRAP to pause the child

test/sys/test_uio.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ fn test_process_vm_readv() {
207207
let mut vector = vec![1u8, 2, 3, 4, 5];
208208

209209
let (r, w) = pipe().unwrap();
210-
match fork().expect("Error: Fork Failed") {
210+
match unsafe {fork()}.expect("Error: Fork Failed") {
211211
Parent { child } => {
212212
close(w).unwrap();
213213
// wait for child

test/sys/test_wait.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fn test_wait_signal() {
1010
let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
1111

1212
// Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
13-
match fork().expect("Error: Fork Failed") {
13+
match unsafe {fork().expect("Error: Fork Failed")} {
1414
Child => {
1515
pause();
1616
unsafe { _exit(123) }
@@ -27,7 +27,7 @@ fn test_wait_exit() {
2727
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
2828

2929
// Safe: Child only calls `_exit`, which is async-signal-safe.
30-
match fork().expect("Error: Fork Failed") {
30+
match unsafe { fork()}.expect("Error: Fork Failed") {
3131
Child => unsafe { _exit(12); },
3232
Parent { child } => {
3333
assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
@@ -47,7 +47,7 @@ fn test_waitstatus_from_raw() {
4747
fn test_waitstatus_pid() {
4848
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
4949

50-
match fork().unwrap() {
50+
match unsafe {fork()}.unwrap() {
5151
Child => unsafe { _exit(0) },
5252
Parent { child } => {
5353
let status = waitpid(child, None).unwrap();
@@ -96,7 +96,7 @@ mod ptrace {
9696
fn test_wait_ptrace() {
9797
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
9898

99-
match fork().expect("Error: Fork Failed") {
99+
match unsafe {fork()}.expect("Error: Fork Failed") {
100100
Child => ptrace_child(),
101101
Parent { child } => ptrace_parent(child),
102102
}

test/test_unistd.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn test_fork_and_waitpid() {
1919
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
2020

2121
// Safe: Child only calls `_exit`, which is signal-safe
22-
match fork().expect("Error: Fork Failed") {
22+
match unsafe {fork()}.expect("Error: Fork Failed") {
2323
Child => unsafe { _exit(0) },
2424
Parent { child } => {
2525
// assert that child was created and pid > 0
@@ -47,7 +47,7 @@ fn test_wait() {
4747
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
4848

4949
// Safe: Child only calls `_exit`, which is signal-safe
50-
match fork().expect("Error: Fork Failed") {
50+
match unsafe {fork()}.expect("Error: Fork Failed") {
5151
Child => unsafe { _exit(0) },
5252
Parent { child } => {
5353
let wait_status = wait();
@@ -191,7 +191,7 @@ macro_rules! execve_test_factory(
191191
// Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function.
192192
// NOTE: Technically, this makes the macro unsafe to use because you could pass anything.
193193
// The tests make sure not to do that, though.
194-
match fork().unwrap() {
194+
match unsafe {fork()}.unwrap() {
195195
Child => {
196196
// Close stdout.
197197
close(1).unwrap();

0 commit comments

Comments
 (0)