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

Rollup of 7 pull requests #85032

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
52fa9da
Rework `wasm::thread` to `thread_atomics`
CDirkx Apr 28, 2021
fab8410
Move `wasm` atomics code to `wasm/atomics`
CDirkx Apr 28, 2021
45bc193
Reuse `unsupported::args` on `wasm`
CDirkx Apr 28, 2021
cf79c06
Fix missing import in `unsupported::args`
CDirkx Apr 28, 2021
6eb4735
Unify rustc and rustdoc parsing of `cfg()`
jyn514 Apr 22, 2021
97658e5
rustc: Support Rust-specific features in -Ctarget-feature
alexcrichton May 6, 2021
fb9feb3
linker: Avoid library duplication with `/WHOLEARCHIVE`
petrochenkov May 3, 2021
31c2ad0
illumos should put libc last in library search order
jclulow May 7, 2021
a9f43a2
std panicking: Make decrease() return ()
ijackson Apr 22, 2021
1b1bf24
std panicking: Provide panic::always_abort
ijackson Apr 20, 2021
3cba120
std panicking: ALWAYS_ABORT: use Relaxed memory ordering
ijackson May 6, 2021
820123a
panic/fork: Command: Do not unwind after fork() in child
ijackson Apr 20, 2021
9283cdc
unix process: pre_exec: Discuss panic safety
ijackson Feb 7, 2021
f801506
panic tests: Command: Test that we do not unwind past fork
ijackson Feb 7, 2021
a17eab7
panic ui test: Provide comprehensive test for panic after fork
ijackson Feb 7, 2021
19429ce
panic ui test: Improve error handling
ijackson Apr 22, 2021
12fe500
panic ui test: Add a test for panic::always_abort
ijackson Apr 22, 2021
756771d
panic ui test: Test always_abort on one thread, panic on another
ijackson Apr 22, 2021
bfa8484
Rearrange SGX split module files
May 7, 2021
fc23b55
Rollup merge of #81858 - ijackson:fork-no-unwind, r=m-ou-se
Dylan-DPC May 7, 2021
3de7bc3
Rollup merge of #84254 - jclulow:illumos-link-order, r=petrochenkov
Dylan-DPC May 7, 2021
2088940
Rollup merge of #84442 - jyn514:doc-cfg, r=petrochenkov
Dylan-DPC May 7, 2021
62f657e
Rollup merge of #84655 - CDirkx:wasm, r=m-ou-se
Dylan-DPC May 7, 2021
e33bcf1
Rollup merge of #84866 - petrochenkov:wholesome, r=Mark-Simulacrum
Dylan-DPC May 7, 2021
c001598
Rollup merge of #84991 - alexcrichton:target-feature-remap, r=nagisa
Dylan-DPC May 7, 2021
bd37dbe
Rollup merge of #85030 - jethrogb:jb/sgx-rearrange-files, r=nagisa
Dylan-DPC May 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,24 +339,32 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
Some(_) | None => {}
};

let filter = |s: &str| {
if s.is_empty() {
return None;
}
let feature = if s.starts_with("+") || s.starts_with("-") {
&s[1..]
} else {
return Some(s.to_string());
};
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
// are not passed down to LLVM.
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
return None;
}
// ... otherwise though we run through `to_llvm_feature` feature when
// passing requests down to LLVM. This means that all in-language
// features also work on the command line instead of having two
// different names when the LLVM name and the Rust name differ.
Some(format!("{}{}", &s[..1], to_llvm_feature(sess, feature)))
};

// Features implied by an implicit or explicit `--target`.
features.extend(
sess.target
.features
.split(',')
.filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
.map(String::from),
);
features.extend(sess.target.features.split(',').filter_map(&filter));

// -Ctarget-features
features.extend(
sess.opts
.cg
.target_feature
.split(',')
.filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
.map(String::from),
);
features.extend(sess.opts.cg.target_feature.split(',').filter_map(&filter));

features
}
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,14 @@ impl<'a> Linker for GccLinker<'a> {
}

fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
if self.sess.target.os == "illumos" && lib.as_str() == "c" {
// libc will be added via late_link_args on illumos so that it will
// appear last in the library search order.
// FIXME: This should be replaced by a more complete and generic
// mechanism for controlling the order of library arguments passed
// to the linker.
return;
}
if !as_needed {
if self.sess.target.is_like_osx {
// FIXME(81490): ld64 doesn't support these flags but macOS 11
Expand Down Expand Up @@ -813,11 +821,9 @@ impl<'a> Linker for MsvcLinker<'a> {
}

fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
self.link_staticlib(lib, verbatim);
self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
}
fn link_whole_rlib(&mut self, path: &Path) {
self.link_rlib(path);
let mut arg = OsString::from("/WHOLEARCHIVE:");
arg.push(path);
self.cmd.arg(arg);
Expand Down
54 changes: 29 additions & 25 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,31 +464,9 @@ impl<'a> StripUnconfigured<'a> {
return true;
}
};
let error = |span, msg, suggestion: &str| {
let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
if !suggestion.is_empty() {
err.span_suggestion(
span,
"expected syntax is",
suggestion.into(),
Applicability::MaybeIncorrect,
);
}
err.emit();
true
};
let span = meta_item.span;
match meta_item.meta_item_list() {
None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
Some([]) => error(span, "`cfg` predicate is not specified", ""),
Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
Some([single]) => match single.meta_item() {
Some(meta_item) => {
attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features)
}
None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
},
}
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
})
})
}

Expand Down Expand Up @@ -532,6 +510,32 @@ impl<'a> StripUnconfigured<'a> {
}
}

pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
let error = |span, msg, suggestion: &str| {
let mut err = sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
if !suggestion.is_empty() {
err.span_suggestion(
span,
"expected syntax is",
suggestion.into(),
Applicability::HasPlaceholders,
);
}
err.emit();
None
};
let span = meta_item.span;
match meta_item.meta_item_list() {
None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
Some([]) => error(span, "`cfg` predicate is not specified", ""),
Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
Some([single]) => match single.meta_item() {
Some(meta_item) => Some(meta_item),
None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
},
}
}

fn is_cfg(sess: &Session, attr: &Attribute) -> bool {
sess.check_name(attr, sym::cfg)
}
11 changes: 11 additions & 0 deletions compiler/rustc_target/src/spec/illumos_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ pub fn opts() -> TargetOptions {
late_link_args.insert(
LinkerFlavor::Gcc,
vec![
// The illumos libc contains a stack unwinding implementation, as
// does libgcc_s. The latter implementation includes several
// additional symbols that are not always in base libc. To force
// the consistent use of just one unwinder, we ensure libc appears
// after libgcc_s in the NEEDED list for the resultant binary by
// ignoring any attempts to add it as a dynamic dependency until the
// very end.
// FIXME: This should be replaced by a more complete and generic
// mechanism for controlling the order of library arguments passed
// to the linker.
"-lc".to_string(),
// LLVM will insert calls to the stack protector functions
// "__stack_chk_fail" and "__stack_chk_guard" into code in native
// object files. Some platforms include these symbols directly in
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/os/unix/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ pub trait CommandExt: Sealed {
/// sure that the closure does not violate library invariants by making
/// invalid use of these duplicates.
///
/// Panicking in the closure is safe only if all the format arguments for the
/// panic message can be safely formatted; this is because although
/// `Command` calls [`std::panic::always_abort`](crate::panic::always_abort)
/// before calling the pre_exec hook, panic will still try to format the
/// panic message.
///
/// When this closure is run, aspects such as the stdio file descriptors and
/// working directory have successfully been changed, so output to these
/// locations may not appear where intended.
Expand Down
36 changes: 36 additions & 0 deletions library/std/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,5 +461,41 @@ pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
panicking::rust_panic_without_hook(payload)
}

/// Make all future panics abort directly without running the panic hook or unwinding.
///
/// There is no way to undo this; the effect lasts until the process exits or
/// execs (or the equivalent).
///
/// # Use after fork
///
/// This function is particularly useful for calling after `libc::fork`. After `fork`, in a
/// multithreaded program it is (on many platforms) not safe to call the allocator. It is also
/// generally highly undesirable for an unwind to unwind past the `fork`, because that results in
/// the unwind propagating to code that was only ever expecting to run in the parent.
///
/// `panic::always_abort()` helps avoid both of these. It directly avoids any further unwinding,
/// and if there is a panic, the abort will occur without allocating provided that the arguments to
/// panic can be formatted without allocating.
///
/// Examples
///
/// ```no_run
/// #![feature(panic_always_abort)]
/// use std::panic;
///
/// panic::always_abort();
///
/// let _ = panic::catch_unwind(|| {
/// panic!("inside the catch");
/// });
///
/// // We will have aborted already, due to the panic.
/// unreachable!();
/// ```
#[unstable(feature = "panic_always_abort", issue = "84438")]
pub fn always_abort() {
crate::panicking::panic_count::set_always_abort();
}

#[cfg(test)]
mod tests;
68 changes: 51 additions & 17 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
fn default_hook(info: &PanicInfo<'_>) {
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
let backtrace_env = if panic_count::get() >= 2 {
let backtrace_env = if panic_count::get_count() >= 2 {
RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full)
} else {
backtrace::rust_backtrace_env()
Expand Down Expand Up @@ -233,6 +233,8 @@ pub mod panic_count {
use crate::cell::Cell;
use crate::sync::atomic::{AtomicUsize, Ordering};

pub const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1);

// Panic count for the current thread.
thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = Cell::new(0) }

Expand All @@ -241,33 +243,53 @@ pub mod panic_count {
// thread, if that thread currently views `GLOBAL_PANIC_COUNT` as being zero,
// then `LOCAL_PANIC_COUNT` in that thread is zero. This invariant holds before
// and after increase and decrease, but not necessarily during their execution.
//
// Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG)
// records whether panic::always_abort() has been called. This can only be
// set, never cleared.
//
// This could be viewed as a struct containing a single bit and an n-1-bit
// value, but if we wrote it like that it would be more than a single word,
// and even a newtype around usize would be clumsy because we need atomics.
// But we use such a tuple for the return type of increase().
//
// Stealing a bit is fine because it just amounts to assuming that each
// panicking thread consumes at least 2 bytes of address space.
static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);

pub fn increase() -> usize {
GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
LOCAL_PANIC_COUNT.with(|c| {
let next = c.get() + 1;
c.set(next);
next
})
pub fn increase() -> (bool, usize) {
(
GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed) & ALWAYS_ABORT_FLAG != 0,
LOCAL_PANIC_COUNT.with(|c| {
let next = c.get() + 1;
c.set(next);
next
}),
)
}

pub fn decrease() -> usize {
pub fn decrease() {
GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed);
LOCAL_PANIC_COUNT.with(|c| {
let next = c.get() - 1;
c.set(next);
next
})
});
}

pub fn set_always_abort() {
GLOBAL_PANIC_COUNT.fetch_or(ALWAYS_ABORT_FLAG, Ordering::Relaxed);
}

pub fn get() -> usize {
// Disregards ALWAYS_ABORT_FLAG
pub fn get_count() -> usize {
LOCAL_PANIC_COUNT.with(|c| c.get())
}

// Disregards ALWAYS_ABORT_FLAG
#[inline]
pub fn is_zero() -> bool {
if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) == 0 {
pub fn count_is_zero() -> bool {
if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) & !ALWAYS_ABORT_FLAG == 0 {
// Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads
// (including the current one) will have `LOCAL_PANIC_COUNT`
// equal to zero, so TLS access can be avoided.
Expand Down Expand Up @@ -410,7 +432,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
/// Determines whether the current thread is unwinding because of panic.
#[inline]
pub fn panicking() -> bool {
!panic_count::is_zero()
!panic_count::count_is_zero()
}

/// The entry point for panicking with a formatted message.
Expand Down Expand Up @@ -563,15 +585,27 @@ fn rust_panic_with_hook(
message: Option<&fmt::Arguments<'_>>,
location: &Location<'_>,
) -> ! {
let panics = panic_count::increase();
let (must_abort, panics) = panic_count::increase();

// If this is the third nested call (e.g., panics == 2, this is 0-indexed),
// the panic hook probably triggered the last panic, otherwise the
// double-panic check would have aborted the process. In this case abort the
// process real quickly as we don't want to try calling it again as it'll
// probably just panic again.
if panics > 2 {
util::dumb_print(format_args!("thread panicked while processing panic. aborting.\n"));
if must_abort || panics > 2 {
if panics > 2 {
// Don't try to print the message in this case
// - perhaps that is causing the recursive panics.
util::dumb_print(format_args!("thread panicked while processing panic. aborting.\n"));
} else {
// Unfortunately, this does not print a backtrace, because creating
// a `Backtrace` will allocate, which we must to avoid here.
let panicinfo = PanicInfo::internal_constructor(message, location);
util::dumb_print(format_args!(
"{}\npanicked after panic::always_abort(), aborting.\n",
panicinfo
));
}
intrinsics::abort()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,8 @@
#[cfg(test)]
mod tests;

/// A doubly-linked list where callers are in charge of memory allocation
/// of the nodes in the list.
mod unsafe_list;

/// Trivial spinlock-based implementation of `sync::Mutex`.
// FIXME: Perhaps use Intel TSX to avoid locking?
mod spin_mutex;
mod unsafe_list;

use crate::num::NonZeroUsize;
use crate::ops::{Deref, DerefMut};
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/sys/sgx/waitqueue/spin_mutex.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! Trivial spinlock-based implementation of `sync::Mutex`.
// FIXME: Perhaps use Intel TSX to avoid locking?

#[cfg(test)]
mod tests;

Expand Down
3 changes: 3 additions & 0 deletions library/std/src/sys/sgx/waitqueue/unsafe_list.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! A doubly-linked list where callers are in charge of memory allocation
//! of the nodes in the list.

#[cfg(test)]
mod tests;

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/unix/process/process_unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl Command {
let (env_lock, pid) = unsafe { (sys::os::env_read_lock(), cvt(libc::fork())?) };

if pid == 0 {
crate::panic::always_abort();
mem::forget(env_lock);
drop(input);
let Err(err) = unsafe { self.do_exec(theirs, envp.as_ref()) };
Expand Down
Loading