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

Add Option to Force Unwind Tables #69984

Merged
merged 1 commit into from
May 5, 2020

Conversation

lenary
Copy link
Contributor

@lenary lenary commented Mar 13, 2020

When panic != unwind, nounwind is added to all functions for a target.
This can cause issues when a panic happens with RUST_BACKTRACE=1, as
there needs to be a way to reconstruct the backtrace. There are three
possible sources of this information: forcing frame pointers (for which
an option exists already), debug info (for which an option exists), or
unwind tables.

Especially for embedded devices, forcing frame pointers can have code
size overheads (RISC-V sees ~10% overheads, ARM sees ~2-3% overheads).
In production code, it can be the case that debug info is not kept, so it is useful
to provide this third option, unwind tables, that users can use to
reconstruct the call stack. Reconstructing this stack is harder than
with frame pointers, but it is still possible.


This came up in discussion on #69890, and turned out to be a fairly simple addition.

r? @hanna-kruppe

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 13, 2020
@@ -593,6 +593,14 @@ impl Session {
}
}

pub fn must_emit_unwind_tables(&self) -> bool {
if let Some(x) = self.opts.cg.force_unwind_tables {
Copy link
Contributor

Choose a reason for hiding this comment

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

As implemented, this allows users to turn off unwinding tables even if the target strictly requires them. That seems like a footgun.

Copy link
Contributor

Choose a reason for hiding this comment

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

should we just error in case of such a conflict?

Copy link
Member

Choose a reason for hiding this comment

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

Emitting an error has prior art in rustc so, yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, Will do when I get back to my work computer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe that I've done this in the right place: validate_commandline_args_with_session_available. This check only takes into account the target definition, not the no_landing_pads that is checked at attribute insertion time.

@hanna-kruppe
Copy link
Contributor

I'm obviously in favor of having this option in some way, but since -C options are effectively "stable" I believe @rust-lang/compiler should sign off the new option.

@nagisa nagisa added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 14, 2020
@nagisa
Copy link
Member

nagisa commented Mar 14, 2020

@rfcbot fcp merge

This introduces an insta-stable argument to control a fairly well understood behaviour of the compilers (not just rustc, but also clang/gcc (-funwind-tables) and others). While the PR itself has some kinks to iron out, this FCP is specifically to gather consensus on merging an insta-stable flag to control whether unwinding tables are emit.

@rfcbot
Copy link

rfcbot commented Mar 14, 2020

Team member @nagisa has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Mar 14, 2020
@Amanieu
Copy link
Member

Amanieu commented Mar 16, 2020

As I commented in #69890:

I personally think that this should be added as a third option to -C panic, called abort-with-backtrace. All it does is enable uwtable to guarantee that backtraces can be reliably generated. The reason for making it separate from -C panic=abort is that this comes at a slight code size increase (due to the need to preserve CSRs even for noreturn functions) and a binary size increase from the .eh_frame section.

On targets which do not support unwinding (e.g. thumb* & riscv*), the standard library would then be built with -C panic=abort-with-backtrace to ensure that reconstructing backtraces is always possible on these targets.

@rust-highfive
Copy link
Collaborator

The job mingw-check of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2020-03-16T16:21:20.3782402Z ========================== Starting Command Output ===========================
2020-03-16T16:21:20.3784856Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/33d15ff7-a5d3-41e6-b2f1-13e71616ed45.sh
2020-03-16T16:21:20.3785130Z 
2020-03-16T16:21:20.3791429Z ##[section]Finishing: Disable git automatic line ending conversion
2020-03-16T16:21:20.3811195Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/69984/merge to s
2020-03-16T16:21:20.3814471Z Task         : Get sources
2020-03-16T16:21:20.3814779Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-03-16T16:21:20.3815077Z Version      : 1.0.0
2020-03-16T16:21:20.3815295Z Author       : Microsoft
---
2020-03-16T16:21:21.6622575Z ##[command]git remote add origin https://github.com/rust-lang/rust
2020-03-16T16:21:21.6638527Z ##[command]git config gc.auto 0
2020-03-16T16:21:21.6648495Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2020-03-16T16:21:22.6585443Z ##[command]git config --get-all http.proxy
2020-03-16T16:21:22.6600588Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/69984/merge:refs/remotes/pull/69984/merge

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @rust-lang/infra. (Feature Requests)

@hanna-kruppe
Copy link
Contributor

@Amanieu Can you elaborate why you think a new -C panic value is better than the independent flag that is proposed here? I don't see any advantage, and some downsides:

  • The panic=unwind/abort choice ties into several other things (which panic runtime is implicitly linked into leaf crates, which rlibs can be linked together) so adding another panic strategy brings unnecessary questions/baggage along.
  • While the motivation for this feature is backtraces on embedded targets, it's not inherently specific to panic=abort. -C force-unwind-tables=on could also help with generating backtraces outside of panics (e.g., profiling or error logging), since some functions can't unwind and wouldn't get an .eh_frame entry even with panic=unwind.

@lenary
Copy link
Contributor Author

lenary commented Mar 16, 2020

@bors retry

@bors
Copy link
Contributor

bors commented Mar 16, 2020

@lenary: 🔑 Insufficient privileges: not in try users

@Amanieu
Copy link
Member

Amanieu commented Mar 16, 2020

One advantage of -C panic is that it can be specified in Cargo.toml.

-C force-unwind-tables=on could also help with generating backtraces outside of panics (e.g., profiling or error logging), since some functions can't unwind and wouldn't get an .eh_frame entry even with panic=unwind.

AFAIK that's not true, when compiling with panic=unwind all functions, regardless of whether they unwind or not, will get the uwtable attribute. The issue with missing backtraces only occurs with panic=abort, hence why I suggested making this an extension of panic=abort.

@hanna-kruppe
Copy link
Contributor

One advantage of -C panic is that it can be specified in Cargo.toml.

Cargo has its own validation of this Cargo.toml entry, so some Cargo changes are required to enable this. And if Cargo changes are required anyway, I don't think it would be significantly harder to add a new force-unwind-tables Cargo.toml key for this.

-C force-unwind-tables=on could also help with generating backtraces outside of panics (e.g., profiling or error logging), since some functions can't unwind and wouldn't get an .eh_frame entry even with panic=unwind.

AFAIK that's not true, when compiling with panic=unwind all functions, regardless of whether they unwind or not, will get the uwtable attribute. The issue with missing backtraces only occurs with panic=abort, hence why I suggested making this an extension of panic=abort.

Ah, right, this is indeed mostly the current behavior. But it is not true for allocator shims, and I don't think the current behavior for other functions is intended or can be expected to last forever.

For historic reasons, certain code paths in the compiler currently decide some unwinding-related things based on the global no_landing_pads property instead of a more precise per-function predicate that e.g. takes #[unwind] attributes into account. Once we clean up our act around unwinding (see also: #65303), I expect that the logic for uwtable being added will also be based on "can this function unwind / are we adding nounwind to it". Generally, the incentives for dropping uwtable from e.g. #[unwind(aborts)] functions are the same as dropping uwtable from all functions in panic=abort mode, just proportionally smaller.

@Amanieu
Copy link
Member

Amanieu commented Mar 18, 2020

Fair enough, I'll withdraw my objection to making this a -C flag.

@nikomatsakis
Copy link
Contributor

@rfcbot reviewed

@Centril Centril added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 2, 2020
@Zoxc
Copy link
Contributor

Zoxc commented Apr 5, 2020

Should we avoid emitting unwind tables by default on Windows (and let people opt-in with this flag)? If not, we probably want an option to turn off unwind tables which this doesn't enable.

@hanna-kruppe
Copy link
Contributor

Given the many different mechanisms and tools that rely on SEH, and Windows gurus stating that pretty much all functions should have unwinding information on x64 Windows, it does not seem very wise to ever omit unwinding tables. Even an opt-out seems dubious to me, and as far as I can tell it's not a feature anyone has ever requested. In fact, after poking at it for a little bit, I can't find any such opt out in MSVC, even when compiling plain C code.

In any case, should we ever change our mind about this, we can still change -Cforce-unwind-tables=no from reporting an error if the target has them enabled by default to override the target's default instead. This is backwards compatible, so it can (and should) be a separate discussion at any point after the flag lands.

@lenary
Copy link
Contributor Author

lenary commented Apr 5, 2020

My understanding is that the self.no_landing_pads() will always be false on windows (that code used to have windows-specific comments by it, which were out of date), so this patch should ensure that you cannot remove unwind tables on windows.

I don't know if i should include that check in the error reporting here: https://github.com/rust-lang/rust/pull/69984/files#diff-eadaa1c9e135801995ae29eaec608049R1173 - happy to update the patch to do so if needed, not sure how it will affect testing.

@hanna-kruppe
Copy link
Contributor

My understanding is that the self.no_landing_pads() will always be false on windows (that code used to have windows-specific comments by it, which were out of date)

I'm pretty sure this is wrong. Session::no_landing_pads() (while it still exists; #70175 removes it) only looks at -C panic and -Z no-landing-pads, neither of which has Windows-related restrictions, so it can easily return true on Windows targets. The target spec field requires_uwtable is taken into account independently of what no_landing_pads() says. This PR even refactors that condition to introduce the must_emit_uwtable.

However, your conclusion (that users can't remove unwinding information on Windows targets) is correct as far as I can tell.

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Apr 9, 2020
@hanna-kruppe
Copy link
Contributor

Thanks!

@bors r+

@bors
Copy link
Contributor

bors commented May 4, 2020

📌 Commit 7f098f637f8efe817ecca975baa9dd71ce018a4f has been approved by hanna-kruppe

@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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 4, 2020
When panic != unwind, `nounwind` is added to all functions for a target.
This can cause issues when a panic happens with RUST_BACKTRACE=1, as
there needs to be a way to reconstruct the backtrace. There are three
possible sources of this information: forcing frame pointers (for which
an option exists already), debug info (for which an option exists), or
unwind tables.

Especially for embedded devices, forcing frame pointers can have code
size overheads (RISC-V sees ~10% overheads, ARM sees ~2-3% overheads).
In code, it can be the case that debug info is not kept, so it is useful
to provide this third option, unwind tables, that users can use to
reconstruct the call stack. Reconstructing this stack is harder than
with frame pointers, but it is still possible.

This commit adds a compiler option which allows a user to force the
addition of unwind tables. Unwind tables cannot be disabled on targets
that require them for correctness, or when using `-C panic=unwind`.
@hanna-kruppe
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented May 4, 2020

📌 Commit cda9946 has been approved by hanna-kruppe

@bors
Copy link
Contributor

bors commented May 4, 2020

⌛ Testing commit cda9946 with merge 753f25e628b9556fd0e963a1027b3883b17d450c...

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request May 4, 2020
…na-kruppe

Add Option to Force Unwind Tables

When panic != unwind, `nounwind` is added to all functions for a target.
This can cause issues when a panic happens with RUST_BACKTRACE=1, as
there needs to be a way to reconstruct the backtrace. There are three
possible sources of this information: forcing frame pointers (for which
an option exists already), debug info (for which an option exists), or
unwind tables.

Especially for embedded devices, forcing frame pointers can have code
size overheads (RISC-V sees ~10% overheads, ARM sees ~2-3% overheads).
In production code, it can be the case that debug info is not kept, so it is useful
to provide this third option, unwind tables, that users can use to
reconstruct the call stack. Reconstructing this stack is harder than
with frame pointers, but it is still possible.

---

This came up in discussion on rust-lang#69890, and turned out to be a fairly simple addition.

r? @hanna-kruppe
@bors
Copy link
Contributor

bors commented May 4, 2020

💔 Test failed - checks-azure

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels May 4, 2020
@hanna-kruppe
Copy link
Contributor

Seems spurious, @bors retry

@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 May 4, 2020
@bors
Copy link
Contributor

bors commented May 5, 2020

⌛ Testing commit cda9946 with merge ac9bfbf737b9450ab6f6e632406e3a403b4e958a...

@Dylan-DPC-zz
Copy link

@bors retry

bors added a commit to rust-lang-ci/rust that referenced this pull request May 5, 2020
Rollup of 4 pull requests

Successful merges:

 - rust-lang#69984 (Add Option to Force Unwind Tables)
 - rust-lang#71830 (Remove clippy from some leftover lists of "possibly failing" tools)
 - rust-lang#71894 (Suggest removing semicolon in last expression only if it's type is known)
 - rust-lang#71897 (Improve docs for embed-bitcode and linker-plugin-lto)

Failed merges:

r? @ghost
@bors
Copy link
Contributor

bors commented May 5, 2020

⌛ Testing commit cda9946 with merge f8d394e...

@bors bors merged commit 12fc1e0 into rust-lang:master May 5, 2020
@lenary lenary deleted the lenary/force-uwtables branch May 30, 2020 13:35
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Aug 6, 2020
While here clean up all pkglint warnings.  Changes since 1.44.1:

Version 1.45.2 (2020-08-03)
==========================

* [Fix bindings in tuple struct patterns][74954]
* [Fix track_caller integration with trait objects][74784]

[74954]: rust-lang/rust#74954
[74784]: rust-lang/rust#74784

Version 1.45.1 (2020-07-30)
==========================

* [Fix const propagation with references.][73613]
* [rustfmt accepts rustfmt_skip in cfg_attr again.][73078]
* [Avoid spurious implicit region bound.][74509]
* [Install clippy on x.py install][74457]

[73613]: rust-lang/rust#73613
[73078]: rust-lang/rust#73078
[74509]: rust-lang/rust#74509
[74457]: rust-lang/rust#74457

Version 1.45.0 (2020-07-16)
==========================

Language
--------
- [Out of range float to int conversions using `as` has been defined as a saturating
  conversion.][71269] This was previously undefined behaviour, but you can use the
   `{f64, f32}::to_int_unchecked` methods to continue using the current behaviour, which
   may be desirable in rare performance sensitive situations.
- [`mem::Discriminant<T>` now uses `T`'s discriminant type instead of always
  using `u64`.][70705]
- [Function like procedural macros can now be used in expression, pattern, and  statement
  positions.][68717] This means you can now use a function-like procedural macro
  anywhere you can use a declarative (`macro_rules!`) macro.

Compiler
--------
- [You can now override individual target features through the `target-feature`
  flag.][72094] E.g. `-C target-feature=+avx2 -C target-feature=+fma` is now
  equivalent to `-C target-feature=+avx2,+fma`.
- [Added the `force-unwind-tables` flag.][69984] This option allows
  rustc to always generate unwind tables regardless of panic strategy.
- [Added the `embed-bitcode` flag.][71716] This codegen flag allows rustc
  to include LLVM bitcode into generated `rlib`s (this is on by default).
- [Added the `tiny` value to the `code-model` codegen flag.][72397]
- [Added tier 3 support\* for the `mipsel-sony-psp` target.][72062]
- [Added tier 3 support for the `thumbv7a-uwp-windows-msvc` target.][72133]

\* Refer to Rust's [platform support page][forge-platform-support] for more
information on Rust's tiered platform support.


Libraries
---------
- [`net::{SocketAddr, SocketAddrV4, SocketAddrV6}` now implements `PartialOrd`
  and `Ord`.][72239]
- [`proc_macro::TokenStream` now implements `Default`.][72234]
- [You can now use `char` with
  `ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}` to iterate over
  a range of codepoints.][72413] E.g.
  you can now write the following;
  ```rust
  for ch in 'a'..='z' {
      print!("{}", ch);
  }
  println!();
  // Prints "abcdefghijklmnopqrstuvwxyz"
  ```
- [`OsString` now implements `FromStr`.][71662]
- [The `saturating_neg` method as been added to all signed integer primitive
  types, and the `saturating_abs` method has been added for all integer
  primitive types.][71886]
- [`Arc<T>`, `Rc<T>` now implement  `From<Cow<'_, T>>`, and `Box` now
  implements `From<Cow>` when `T` is `[T: Copy]`, `str`, `CStr`, `OsStr`,
  or `Path`.][71447]
- [`Box<[T]>` now implements `From<[T; N]>`.][71095]
- [`BitOr` and `BitOrAssign` are implemented for all `NonZero`
  integer types.][69813]
- [The `fetch_min`, and `fetch_max` methods have been added to all atomic
  integer types.][72324]
- [The `fetch_update` method has been added to all atomic integer types.][71843]

Stabilized APIs
---------------
- [`Arc::as_ptr`]
- [`BTreeMap::remove_entry`]
- [`Rc::as_ptr`]
- [`rc::Weak::as_ptr`]
- [`rc::Weak::from_raw`]
- [`rc::Weak::into_raw`]
- [`str::strip_prefix`]
- [`str::strip_suffix`]
- [`sync::Weak::as_ptr`]
- [`sync::Weak::from_raw`]
- [`sync::Weak::into_raw`]
- [`char::UNICODE_VERSION`]
- [`Span::resolved_at`]
- [`Span::located_at`]
- [`Span::mixed_site`]
- [`unix::process::CommandExt::arg0`]

Cargo
-----

Misc
----
- [Rustdoc now supports strikethrough text in Markdown.][71928] E.g.
  `~~outdated information~~` becomes "~~outdated information~~".
- [Added an emoji to Rustdoc's deprecated API message.][72014]

Compatibility Notes
-------------------
- [Trying to self initialize a static value (that is creating a value using
  itself) is unsound and now causes a compile error.][71140]
- [`{f32, f64}::powi` now returns a slightly different value on Windows.][73420]
  This is due to changes in LLVM's intrinsics which `{f32, f64}::powi` uses.
- [Rustdoc's CLI's extra error exit codes have been removed.][71900] These were
  previously undocumented and not intended for public use. Rustdoc still provides
  a non-zero exit code on errors.

Internals Only
--------------
- [Make clippy a git subtree instead of a git submodule][70655]
- [Unify the undo log of all snapshot types][69464]

[73420]: rust-lang/rust#73420
[72324]: rust-lang/rust#72324
[71843]: rust-lang/rust#71843
[71886]: rust-lang/rust#71886
[72234]: rust-lang/rust#72234
[72239]: rust-lang/rust#72239
[72397]: rust-lang/rust#72397
[72413]: rust-lang/rust#72413
[72014]: rust-lang/rust#72014
[72062]: rust-lang/rust#72062
[72094]: rust-lang/rust#72094
[72133]: rust-lang/rust#72133
[71900]: rust-lang/rust#71900
[71928]: rust-lang/rust#71928
[71662]: rust-lang/rust#71662
[71716]: rust-lang/rust#71716
[71447]: rust-lang/rust#71447
[71269]: rust-lang/rust#71269
[71095]: rust-lang/rust#71095
[71140]: rust-lang/rust#71140
[70655]: rust-lang/rust#70655
[70705]: rust-lang/rust#70705
[69984]: rust-lang/rust#69984
[69813]: rust-lang/rust#69813
[69464]: rust-lang/rust#69464
[68717]: rust-lang/rust#68717
[`Arc::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.as_ptr
[`BTreeMap::remove_entry`]: https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.remove_entry
[`Rc::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.as_ptr
[`rc::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.as_ptr
[`rc::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.from_raw
[`rc::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.into_raw
[`sync::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.as_ptr
[`sync::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.from_raw
[`sync::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.into_raw
[`str::strip_prefix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_prefix
[`str::strip_suffix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_suffix
[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/stable/std/char/constant.UNICODE_VERSION.html
[`Span::resolved_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.resolved_at
[`Span::located_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.located_at
[`Span::mixed_site`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.mixed_site
[`unix::process::CommandExt::arg0`]: https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.arg0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet