Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use libc::sigaction() instead of sys::signal() to prevent a deadlock #88828

Merged
merged 3 commits into from
Oct 6, 2021

Conversation

FabianWolff
Copy link
Contributor

@FabianWolff FabianWolff commented Sep 10, 2021

Fixes #88585. POSIX specifies that after forking,

to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.

Rust's standard library does not currently adhere to this, as evidenced by #88585. The child process calls sys::signal(), which on Android calls libc::dlsym(), which is not async-signal-safe, and in fact causes a deadlock in the example in #88585.

I think the easiest solution here would be to just call libc::sigaction() instead, which is async-signal-safe, provides the functionality we need, and is apparently available on all Android versions because it is also used e.g. here.

@rust-highfive
Copy link
Collaborator

r? @dtolnay

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 10, 2021
@rust-log-analyzer

This comment has been minimized.

@hacker-volodya
Copy link

I've tested the fix on Android Emulator x86-64 (Android 10), and on real devices (Android from 6.0.1 to 11). It works!

Locking g_dl_mutex...
Spawning ps...
ps spawned!
USER            PID   PPID     VSZ    RSS WCHAN            ADDR S NAME
shell          5002  25748 10790496  2692 futex_wait_queue_me 0 S linker-deadlock
shell          5005   5002 10774564  3368 0                   0 R ps
dlsym'ing done
Done

@FabianWolff
Copy link
Contributor Author

I've tested the fix on Android Emulator x86-64 (Android 10), and on real devices (Android from 6.0.1 to 11). It works!

Happy to hear that! And thanks a lot for testing this @d3fl4t3!

Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This looks good.

library/std/src/sys/unix/process/process_unix.rs Outdated Show resolved Hide resolved
The reference automatically coerces to a pointer. Writing an explicit
cast here is slightly misleading because that's most commonly used when
a pointer needs to be converted from one pointer type to another, e.g.
`*const c_void` to `*const sigaction` or vice versa.
@dtolnay
Copy link
Member

dtolnay commented Sep 29, 2021

@bors r+

@bors
Copy link
Contributor

bors commented Sep 29, 2021

📌 Commit e3e5ae9 has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 29, 2021
Manishearth added a commit to Manishearth/rust that referenced this pull request Sep 30, 2021
Use `libc::sigaction()` instead of `sys::signal()` to prevent a deadlock

Fixes rust-lang#88585. POSIX [specifies](https://man7.org/linux/man-pages/man3/fork.3p.html) that after forking,
> to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.

Rust's standard library does not currently adhere to this, as evidenced by rust-lang#88585. The child process calls [`sys::signal()`](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/android.rs#L76), which on Android calls [`libc::dlsym()`](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/weak.rs#L101), which is [**not**](https://man7.org/linux/man-pages/man7/signal-safety.7.html) async-signal-safe, and in fact causes a deadlock in the example in rust-lang#88585.

I think the easiest solution here would be to just call `libc::sigaction()` instead, which [is](https://man7.org/linux/man-pages/man7/signal-safety.7.html) async-signal-safe, provides the functionality we need, and is apparently available on all Android versions because it is also used e.g. [here](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/stack_overflow.rs#L112-L114).
@Manishearth
Copy link
Member

@bors r-

#89402 (comment)

warning: dropping unsupported crate type `dylib` for target `x86_64-unknown-redox`

error[E0609]: no field `sa_sigaction` on type `sigaction`
    |
    |
337 |             action.sa_sigaction = libc::SIG_DFL;
    |
    |
    = note: available fields are: `sa_handler`, `sa_flags`, `sa_restorer`, `sa_mask`
For more information about this error, try `rustc --explain E0609`.
[RUSTC-TIMING] std test:false 2.497
warning: `std` (lib) generated 1 warning

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Sep 30, 2021
@FabianWolff
Copy link
Contributor Author

So neither .sa_sigaction nor .sa_handler are universally available, and there doesn't seem to be an easy way to detect which platform uses which field name. I have therefore restricted my original fix to just Android for now (which is the platform that #88585 was discovered on).

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 1, 2021
@dtolnay
Copy link
Member

dtolnay commented Oct 3, 2021

@bors r+

@bors
Copy link
Contributor

bors commented Oct 3, 2021

📌 Commit 65ef265 has been approved by dtolnay

@bors bors removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 3, 2021
@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Oct 3, 2021
Manishearth added a commit to Manishearth/rust that referenced this pull request Oct 5, 2021
Use `libc::sigaction()` instead of `sys::signal()` to prevent a deadlock

Fixes rust-lang#88585. POSIX [specifies](https://man7.org/linux/man-pages/man3/fork.3p.html) that after forking,
> to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.

Rust's standard library does not currently adhere to this, as evidenced by rust-lang#88585. The child process calls [`sys::signal()`](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/android.rs#L76), which on Android calls [`libc::dlsym()`](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/weak.rs#L101), which is [**not**](https://man7.org/linux/man-pages/man7/signal-safety.7.html) async-signal-safe, and in fact causes a deadlock in the example in rust-lang#88585.

I think the easiest solution here would be to just call `libc::sigaction()` instead, which [is](https://man7.org/linux/man-pages/man7/signal-safety.7.html) async-signal-safe, provides the functionality we need, and is apparently available on all Android versions because it is also used e.g. [here](https://github.com/rust-lang/rust/blob/7bf0736e130e2203c58654f7353dbf9575e49d5c/library/std/src/sys/unix/stack_overflow.rs#L112-L114).
bors added a commit to rust-lang-ci/rust that referenced this pull request Oct 5, 2021
…arth

Rollup of 10 pull requests

Successful merges:

 - rust-lang#88706 (Normalize associated type projections when checking return type of main)
 - rust-lang#88828 (Use `libc::sigaction()` instead of `sys::signal()` to prevent a deadlock)
 - rust-lang#88871 (Fix suggestion for nested struct patterns)
 - rust-lang#89317 (Move generic error message to separate branches)
 - rust-lang#89351 (for signed wrapping remainder, do not compare lhs with MIN)
 - rust-lang#89442 (Add check for duplicated doc aliases)
 - rust-lang#89502 (Fix Lower/UpperExp formatting for integers and precision zero)
 - rust-lang#89523 (Make `proc_macro_derive_resolution_fallback` a future-breakage lint)
 - rust-lang#89532 (Document behavior of  `MaybeLiveLocals` regarding enums and field-senstivity)
 - rust-lang#89546 (Make an initial guess for metadata size to reduce buffer resizes)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit eb86098 into rust-lang:master Oct 6, 2021
@rustbot rustbot added this to the 1.57.0 milestone Oct 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

deadlock: Command::spawn is trying to dlsym after fork, but linker mutex is locked
8 participants