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

aborts: Clarify documentation and comments #85377

Merged
merged 7 commits into from
Jul 5, 2021
Merged

Conversation

ijackson
Copy link
Contributor

@ijackson ijackson commented May 16, 2021

In the docs for intrinsics::abort():

  • Strengthen the recommendation by to use process::abort instead.
  • Document the fact that it sometimes (ab)uses an LLVM debug trap and what the likely consequences are.
  • State that the precise behaviour is unstable.

In the docs for process::abort():

  • Promise that we have the same behaviour as C abort().
  • Document the likely consequences, including, specifically, the consequences on Unix.

In the internal comment for unix::abort_internal:

  • Refer to the public docs for the public API functions.
  • Correct and expand the description of libc::abort. Specifically:
  • Do not claim that abort() unregisters signal handlers. It doesn't; it honours the SIGABRT handler.
  • Discuss, extensively, the issue with abort() flushing stdio buffers.
  • Describe the glibc behaviour in some detail.

Co-authored-by: Mark Wooding mdw@distorted.org.uk
Signed-off-by: Ian Jackson ijackson@chiark.greenend.org.uk

Fixes #40230

@rust-highfive
Copy link
Collaborator

r? @m-ou-se

(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 May 16, 2021
@ijackson
Copy link
Contributor Author

I have a WIP branch to make panic aborts all be libc::abort but it's not ready yet.

@Urgau
Copy link
Member

Urgau commented May 16, 2021

I have a WIP branch to make panic aborts all be libc::abort but it's not ready yet.

How will you handle system that don't have libc or not even an OS ?

@ijackson
Copy link
Contributor Author

How will you handle system that don't have libc or not even an OS ?

This is in std, and (IIRC, without reminding myself by looking at the code again) the answer is by calling abort_internal. But let us discuss that in the MR for that other branch when I have it prepared. Right now it doesn't actually work completely right :-).

// See the public documentation for `intrinsics::abort()` and `process::abort()`
// for further discussion.
//
// There is confusion about whether libc::abort() flushes stdio streams.
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps mention it is implementation-defined as a first point (C18 7.22.4.1p1).

// for further discussion.
//
// There is confusion about whether libc::abort() flushes stdio streams.
// libc::abort() is required by ISO C 99 (7.14.1.1p5) to be async-signal-safe,
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be better to point to C18 (it is still 7.14.1.1p5).

library/std/src/sys/unix/mod.rs Show resolved Hide resolved
@SimonSapin
Copy link
Contributor

What motivated opening #40230 is that Servo has a "crash handler" registered for SEGV, ILL, IOT, and BUS signals that prints the stack/backtrace of the current thread then aborts the process. These backtraces have proven many times essential in debugging crashes that happen during automated CI.

When aborting with std::process::abort we encountered a bug where the signal handler would be called in a loop. This is consistent with this PR’s comment that libc::abort may trigger one of the registered signals. The best (least worse) work-around we found at the time was to use std::intrinsics::abort instead, despite the recommendation to prefer std::process::abort: servo/servo#16899. Now I realize that a better fix might have been to have the handler unregister itself the first time it runs?

@ijackson
Copy link
Contributor Author

What motivated opening #40230 is that Servo has a "crash handler" registered for SEGV, ILL, IOT, and BUS signals that prints the stack/backtrace of the current thread then aborts the process. These backtraces have proven many times essential in debugging crashes that happen during automated CI.

Yes, this is not an uncommon technique. I'm not sure, though, why ABRT wasn't in your list there.

When aborting with std::process::abort we encountered a bug where the signal handler would be called in a loop. This is consistent with this PR’s comment that libc::abort may trigger one of the registered signals. The best (least worse) work-around we found at the time was to use std::intrinsics::abort instead, despite the recommendation to prefer std::process::abort: servo/servo#16899. Now I realize that a better fix might have been to have the handler unregister itself the first time it runs?

Yes, the usual approach to this problem is indeed to make sure the signal handler does not run recursively. You can easily have the kernel reset the signal handler for you: pass the SA_RESETHAND flag in sa_flags when calling sigaction.

Do you think my docs here would have been sufficient to help your former selves? :-)

@SimonSapin
Copy link
Contributor

I'm not sure, though, why ABRT wasn't in your list there.

I’m not sure either. Presumably printing the stack is less useful in cases of deliberate abort than for crashes caused by Undefined Behavior?

I just realized that it’s the intrinsics::abort docs that mention SIGILL and SIGSEGV, but the process::abort docs only mention SIGART, which is not consistent with how we observed the looped/recursive handler at the time :/

@crlf0710 crlf0710 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 5, 2021
Comment on lines 718 to 727
/// The current implementation of `intrinsics::abort` (ab)uses a debug trap
/// on some popular platforms.
/// On Unix, the
/// process will probably die of a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or
/// `SIGBUS`. The precise behaviour is not guaranteed and not stable.
Copy link
Member

Choose a reason for hiding this comment

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

Two notes:

  • I don't think there's much use in calling this 'abuse'.
  • In the rest of std we use the word 'terminate' instead of 'die' for processes.

How about something like this?

Suggested change
/// The current implementation of `intrinsics::abort` (ab)uses a debug trap
/// on some popular platforms.
/// On Unix, the
/// process will probably die of a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or
/// `SIGBUS`. The precise behaviour is not guaranteed and not stable.
/// The current implementation of `intrinsics::abort` results in an invalid
/// instruction on most platforms. On Unix, this will probably cause the
/// process to be terminated with a signal like `SIGABRT`, `SIGILL`,
/// `SIGTRAP`, `SIGSEGV` or `SIGBUS`. The precise behaviour is not
/// guaranteed and not stable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thaks for the attention. I have more-or-less adopted your suggestions. I preferred a more active voice.

@ijackson
Copy link
Contributor Author

ijackson commented Jun 7, 2021

I have (belatedly) enabled the pre-push hook that stops me pushing those empty WIP commits. Apologies for the noise.

@crlf0710 crlf0710 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 26, 2021
@bors
Copy link
Contributor

bors commented Jul 2, 2021

☔ The latest upstream changes (presumably #86817) made this pull request unmergeable. Please resolve the merge conflicts.

ijackson and others added 5 commits July 5, 2021 12:43
In the docs for intrinsics::abort():

 * Strengthen the recommendation by to use process::abort instead.
 * Document the fact that it (ab)uses an LLVM debug trap and what the
   likely consequences are.
 * State that the precise behaviour is unstable.

In the docs for process::abort():

 * Promise that we have the same behaviour as C `abort()`.
 * Document the likely consequences, including, specifically, the
   consequences on Unix.

In the internal comment for unix::abort_internal:

 * Refer to the public docs for the public API functions.
 * Correct and expand the description of libc::abort.  Specifically:
 * Do not claim that abort() unregisters signal handlers.  It doesn't;
   it honours the SIGABRT handler.
 * Discuss, extensively, the issue with abort() flushing stdio buffers.
 * Describe the glibc behaviour in some detail.

Co-authored-by: Mark Wooding <mdw@distorted.org.uk>
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
As per discussion here
 rust-lang#85377 (review)

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
There is discussion of this in rust-lang#40230 which requests clarification.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
And withdraw the allegation of "abuse".

Adapted from a suggestion by @m-ou-se.

Co-authored-by: Mara Bos <m-ou.se@m-ou.se>
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Adapted from a suggestion by @m-ou-se.

Co-authored-by: Mara Bos <m-ou.se@m-ou.se>
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
@m-ou-se
Copy link
Member

m-ou-se commented Jul 5, 2021

Applied a suggestion and rebased for a merge conflict.

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Jul 5, 2021

📌 Commit 08d912f has been approved by m-ou-se

@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 Jul 5, 2021
@ijackson
Copy link
Contributor Author

ijackson commented Jul 5, 2021 via email

bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 5, 2021
Rollup of 7 pull requests

Successful merges:

 - rust-lang#83581 (Add std::os::unix::fs::DirEntryExt2::file_name_ref(&self) -> &OsStr)
 - rust-lang#85377 (aborts: Clarify documentation and comments)
 - rust-lang#86685 (double-check mutability inside Allocation)
 - rust-lang#86794 (Stabilize `Seek::rewind()`)
 - rust-lang#86852 (Remove some doc aliases)
 - rust-lang#86878 (:arrow_up: rust-analyzer)
 - rust-lang#86886 (Remove `impl Clean for {Ident, Symbol}`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit add24d2 into rust-lang:master Jul 5, 2021
@rustbot rustbot added this to the 1.55.0 milestone Jul 5, 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.

Document differences between std::process::abort and std::intrinsics::abort