mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Rollup merge of #124480 - Enselic:on-broken-pipe, r=jieyouxu
Change `SIGPIPE` ui from `#[unix_sigpipe = "..."]` to `-Zon-broken-pipe=...` In the stabilization [attempt](https://github.com/rust-lang/rust/pull/120832) of `#[unix_sigpipe = "sig_dfl"]`, a concern was [raised ](https://github.com/rust-lang/rust/pull/120832#issuecomment-2007394609) related to using a language attribute for the feature: Long term, we want `fn lang_start()` to be definable by any crate, not just libstd. Having a special language attribute in that case becomes awkward. So as a first step towards the next stabilization attempt, this PR changes the `#[unix_sigpipe = "..."]` attribute to a compiler flag `-Zon-broken-pipe=...` to remove that concern, since now the language is not "contaminated" by this feature. Another point was [also raised](https://github.com/rust-lang/rust/pull/120832#issuecomment-1987023484), namely that the ui should not leak **how** it does things, but rather what the **end effect** is. The new flag uses the proposed naming. This is of course something that can be iterated on further before stabilization. Tracking issue: https://github.com/rust-lang/rust/issues/97889
This commit is contained in:
commit
9dfd527c6f
@ -1,5 +1,3 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
// A note about jemalloc: rustc uses jemalloc when built for CI and
|
||||||
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
||||||
// mechanism. However, for complicated reasons (see
|
// mechanism. However, for complicated reasons (see
|
||||||
@ -34,7 +32,6 @@
|
|||||||
// https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef
|
// https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef
|
||||||
// for an example of how to do so.
|
// for an example of how to do so.
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_dfl"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// See the comment at the top of this file for an explanation of this.
|
// See the comment at the top of this file for an explanation of this.
|
||||||
#[cfg(feature = "jemalloc-sys")]
|
#[cfg(feature = "jemalloc-sys")]
|
||||||
|
@ -396,10 +396,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Entry point:
|
// Entry point:
|
||||||
gated!(
|
|
||||||
unix_sigpipe, Normal, template!(NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing,
|
|
||||||
EncodeCrossCrate::Yes, experimental!(unix_sigpipe)
|
|
||||||
),
|
|
||||||
ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||||
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||||
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||||
|
@ -619,8 +619,6 @@ declare_features! (
|
|||||||
/// Allows creation of instances of a struct by moving fields that have
|
/// Allows creation of instances of a struct by moving fields that have
|
||||||
/// not changed from prior instances of the same struct (RFC #2528)
|
/// not changed from prior instances of the same struct (RFC #2528)
|
||||||
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
||||||
/// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
|
|
||||||
(unstable, unix_sigpipe, "1.65.0", Some(97889)),
|
|
||||||
/// Allows unnamed fields of struct and union type
|
/// Allows unnamed fields of struct and union type
|
||||||
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
|
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
|
||||||
/// Allows unsized fn parameters.
|
/// Allows unsized fn parameters.
|
||||||
|
@ -20,7 +20,7 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
|
|||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{FileName, SourceFileHashAlgorithm};
|
use rustc_span::{FileName, SourceFileHashAlgorithm};
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel, WasmCAbi,
|
CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi,
|
||||||
};
|
};
|
||||||
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
|
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
@ -809,6 +809,7 @@ fn test_unstable_options_tracking_hash() {
|
|||||||
tracked!(no_profiler_runtime, true);
|
tracked!(no_profiler_runtime, true);
|
||||||
tracked!(no_trait_vptr, true);
|
tracked!(no_trait_vptr, true);
|
||||||
tracked!(no_unique_section_names, true);
|
tracked!(no_unique_section_names, true);
|
||||||
|
tracked!(on_broken_pipe, OnBrokenPipe::Kill);
|
||||||
tracked!(oom, OomStrategy::Panic);
|
tracked!(oom, OomStrategy::Panic);
|
||||||
tracked!(osx_rpath_install_name, true);
|
tracked!(osx_rpath_install_name, true);
|
||||||
tracked!(packed_bundled_libs, true);
|
tracked!(packed_bundled_libs, true);
|
||||||
|
@ -695,9 +695,6 @@ passes_transparent_incompatible =
|
|||||||
passes_undefined_naked_function_abi =
|
passes_undefined_naked_function_abi =
|
||||||
Rust ABI is unsupported in naked functions
|
Rust ABI is unsupported in naked functions
|
||||||
|
|
||||||
passes_unix_sigpipe_values =
|
|
||||||
valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
|
|
||||||
|
|
||||||
passes_unknown_external_lang_item =
|
passes_unknown_external_lang_item =
|
||||||
unknown external lang item: `{$lang_item}`
|
unknown external lang item: `{$lang_item}`
|
||||||
|
|
||||||
|
@ -2523,7 +2523,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
|
|||||||
sym::automatically_derived,
|
sym::automatically_derived,
|
||||||
sym::start,
|
sym::start,
|
||||||
sym::rustc_main,
|
sym::rustc_main,
|
||||||
sym::unix_sigpipe,
|
|
||||||
sym::derive,
|
sym::derive,
|
||||||
sym::test,
|
sym::test,
|
||||||
sym::test_case,
|
sym::test_case,
|
||||||
|
@ -12,8 +12,7 @@ use rustc_span::symbol::sym;
|
|||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain,
|
AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr,
|
||||||
MultipleStartFunctions, NoMainErr, UnixSigpipeValues,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EntryContext<'tcx> {
|
struct EntryContext<'tcx> {
|
||||||
@ -67,11 +66,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
|||||||
ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
|
ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
|
||||||
);
|
);
|
||||||
match entry_point_type {
|
match entry_point_type {
|
||||||
EntryPointType::None => {
|
EntryPointType::None => (),
|
||||||
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
|
|
||||||
ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
|
_ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
|
||||||
for attr in [sym::start, sym::rustc_main] {
|
for attr in [sym::start, sym::rustc_main] {
|
||||||
if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
|
if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
|
||||||
@ -81,9 +76,6 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
|||||||
}
|
}
|
||||||
EntryPointType::MainNamed => (),
|
EntryPointType::MainNamed => (),
|
||||||
EntryPointType::OtherMain => {
|
EntryPointType::OtherMain => {
|
||||||
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
|
|
||||||
ctxt.tcx.dcx().emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
|
|
||||||
}
|
|
||||||
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
|
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
|
||||||
}
|
}
|
||||||
EntryPointType::RustcMainAttr => {
|
EntryPointType::RustcMainAttr => {
|
||||||
@ -98,9 +90,6 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntryPointType::Start => {
|
EntryPointType::Start => {
|
||||||
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
|
|
||||||
ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
|
|
||||||
}
|
|
||||||
if ctxt.start_fn.is_none() {
|
if ctxt.start_fn.is_none() {
|
||||||
ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
|
ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
|
||||||
} else {
|
} else {
|
||||||
@ -120,7 +109,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
|
|||||||
Some((def_id.to_def_id(), EntryFnType::Start))
|
Some((def_id.to_def_id(), EntryFnType::Start))
|
||||||
} else if let Some((local_def_id, _)) = visitor.attr_main_fn {
|
} else if let Some((local_def_id, _)) = visitor.attr_main_fn {
|
||||||
let def_id = local_def_id.to_def_id();
|
let def_id = local_def_id.to_def_id();
|
||||||
Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }))
|
Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
|
||||||
} else {
|
} else {
|
||||||
if let Some(main_def) = tcx.resolutions(()).main_def
|
if let Some(main_def) = tcx.resolutions(()).main_def
|
||||||
&& let Some(def_id) = main_def.opt_fn_def_id()
|
&& let Some(def_id) = main_def.opt_fn_def_id()
|
||||||
@ -133,31 +122,19 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }));
|
return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }));
|
||||||
}
|
}
|
||||||
no_main_err(tcx, visitor);
|
no_main_err(tcx, visitor);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
|
fn sigpipe(tcx: TyCtxt<'_>) -> u8 {
|
||||||
if let Some(attr) = tcx.get_attr(def_id, sym::unix_sigpipe) {
|
match tcx.sess.opts.unstable_opts.on_broken_pipe {
|
||||||
match (attr.value_str(), attr.meta_item_list()) {
|
rustc_target::spec::OnBrokenPipe::Default => sigpipe::DEFAULT,
|
||||||
(Some(sym::inherit), None) => sigpipe::INHERIT,
|
rustc_target::spec::OnBrokenPipe::Kill => sigpipe::SIG_DFL,
|
||||||
(Some(sym::sig_ign), None) => sigpipe::SIG_IGN,
|
rustc_target::spec::OnBrokenPipe::Error => sigpipe::SIG_IGN,
|
||||||
(Some(sym::sig_dfl), None) => sigpipe::SIG_DFL,
|
rustc_target::spec::OnBrokenPipe::Inherit => sigpipe::INHERIT,
|
||||||
(Some(_), None) => {
|
|
||||||
tcx.dcx().emit_err(UnixSigpipeValues { span: attr.span });
|
|
||||||
sigpipe::DEFAULT
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Keep going so that `fn emit_malformed_attribute()` can print
|
|
||||||
// an excellent error message
|
|
||||||
sigpipe::DEFAULT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sigpipe::DEFAULT
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1259,13 +1259,6 @@ pub struct ExternMain {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(passes_unix_sigpipe_values)]
|
|
||||||
pub struct UnixSigpipeValues {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NoMainErr {
|
pub struct NoMainErr {
|
||||||
pub sp: Span,
|
pub sp: Span,
|
||||||
pub crate_name: Symbol,
|
pub crate_name: Symbol,
|
||||||
|
@ -2909,7 +2909,9 @@ pub(crate) mod dep_tracking {
|
|||||||
use rustc_feature::UnstableFeatures;
|
use rustc_feature::UnstableFeatures;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::RealFileName;
|
use rustc_span::RealFileName;
|
||||||
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel, WasmCAbi};
|
use rustc_target::spec::{
|
||||||
|
CodeModel, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi,
|
||||||
|
};
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
|
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
|
||||||
};
|
};
|
||||||
@ -2973,6 +2975,7 @@ pub(crate) mod dep_tracking {
|
|||||||
InstrumentXRay,
|
InstrumentXRay,
|
||||||
CrateType,
|
CrateType,
|
||||||
MergeFunctions,
|
MergeFunctions,
|
||||||
|
OnBrokenPipe,
|
||||||
PanicStrategy,
|
PanicStrategy,
|
||||||
RelroLevel,
|
RelroLevel,
|
||||||
OptLevel,
|
OptLevel,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! NOTE: Keep these constants in sync with `library/std/src/sys/pal/unix/mod.rs`!
|
//! NOTE: Keep these constants in sync with `library/std/src/sys/pal/unix/mod.rs`!
|
||||||
|
|
||||||
/// The default value if `#[unix_sigpipe]` is not specified. This resolves
|
/// The default value if `-Zon-broken-pipe=...` is not specified. This resolves
|
||||||
/// to `SIG_IGN` in `library/std/src/sys/pal/unix/mod.rs`.
|
/// to `SIG_IGN` in `library/std/src/sys/pal/unix/mod.rs`.
|
||||||
///
|
///
|
||||||
/// Note that `SIG_IGN` has been the Rust default since 2014. See
|
/// Note that `SIG_IGN` has been the Rust default since 2014. See
|
||||||
|
@ -12,7 +12,7 @@ use rustc_span::edition::Edition;
|
|||||||
use rustc_span::RealFileName;
|
use rustc_span::RealFileName;
|
||||||
use rustc_span::SourceFileHashAlgorithm;
|
use rustc_span::SourceFileHashAlgorithm;
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet, WasmCAbi,
|
CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, SanitizerSet, WasmCAbi,
|
||||||
};
|
};
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
|
RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
|
||||||
@ -378,6 +378,7 @@ mod desc {
|
|||||||
pub const parse_time_passes_format: &str = "`text` (default) or `json`";
|
pub const parse_time_passes_format: &str = "`text` (default) or `json`";
|
||||||
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
||||||
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
||||||
|
pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
|
||||||
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
||||||
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
|
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
|
||||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
||||||
@ -708,6 +709,17 @@ mod parse {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_on_broken_pipe(slot: &mut OnBrokenPipe, v: Option<&str>) -> bool {
|
||||||
|
match v {
|
||||||
|
// OnBrokenPipe::Default can't be explicitly specified
|
||||||
|
Some("kill") => *slot = OnBrokenPipe::Kill,
|
||||||
|
Some("error") => *slot = OnBrokenPipe::Error,
|
||||||
|
Some("inherit") => *slot = OnBrokenPipe::Inherit,
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
|
pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
|
||||||
match v {
|
match v {
|
||||||
Some("panic") => *slot = OomStrategy::Panic,
|
Some("panic") => *slot = OomStrategy::Panic,
|
||||||
@ -1833,6 +1845,8 @@ options! {
|
|||||||
"do not use unique names for text and data sections when -Z function-sections is used"),
|
"do not use unique names for text and data sections when -Z function-sections is used"),
|
||||||
normalize_docs: bool = (false, parse_bool, [TRACKED],
|
normalize_docs: bool = (false, parse_bool, [TRACKED],
|
||||||
"normalize associated items in rustdoc when generating documentation"),
|
"normalize associated items in rustdoc when generating documentation"),
|
||||||
|
on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED],
|
||||||
|
"behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"),
|
||||||
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
|
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
|
||||||
"panic strategy for out-of-memory handling"),
|
"panic strategy for out-of-memory handling"),
|
||||||
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
||||||
|
@ -1936,7 +1936,6 @@ symbols! {
|
|||||||
unit,
|
unit,
|
||||||
universal_impl_trait,
|
universal_impl_trait,
|
||||||
unix,
|
unix,
|
||||||
unix_sigpipe,
|
|
||||||
unlikely,
|
unlikely,
|
||||||
unmarked_api,
|
unmarked_api,
|
||||||
unnamed_fields,
|
unnamed_fields,
|
||||||
|
@ -778,6 +778,14 @@ pub enum PanicStrategy {
|
|||||||
Abort,
|
Abort,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||||
|
pub enum OnBrokenPipe {
|
||||||
|
Default,
|
||||||
|
Kill,
|
||||||
|
Error,
|
||||||
|
Inherit,
|
||||||
|
}
|
||||||
|
|
||||||
impl PanicStrategy {
|
impl PanicStrategy {
|
||||||
pub fn desc(&self) -> &str {
|
pub fn desc(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -74,7 +74,7 @@ macro_rules! rtunwrap {
|
|||||||
//
|
//
|
||||||
// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
|
// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
|
||||||
// `SIG_IGN`. Applications have good reasons to want a different behavior
|
// `SIG_IGN`. Applications have good reasons to want a different behavior
|
||||||
// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that
|
// though, so there is a `-Zon-broken-pipe` compiler flag that
|
||||||
// can be used to select how `SIGPIPE` shall be setup (if changed at all) before
|
// can be used to select how `SIGPIPE` shall be setup (if changed at all) before
|
||||||
// `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889>
|
// `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889>
|
||||||
// for more info.
|
// for more info.
|
||||||
|
@ -55,8 +55,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
|
|||||||
// want!
|
// want!
|
||||||
//
|
//
|
||||||
// Hence, we set SIGPIPE to ignore when the program starts up in order
|
// Hence, we set SIGPIPE to ignore when the program starts up in order
|
||||||
// to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to
|
// to prevent this problem. Use `-Zon-broken-pipe=...` to alter this
|
||||||
// alter this behavior.
|
// behavior.
|
||||||
reset_sigpipe(sigpipe);
|
reset_sigpipe(sigpipe);
|
||||||
|
|
||||||
stack_overflow::init();
|
stack_overflow::init();
|
||||||
@ -190,7 +190,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
if sigpipe_attr_specified {
|
if sigpipe_attr_specified {
|
||||||
UNIX_SIGPIPE_ATTR_SPECIFIED.store(true, crate::sync::atomic::Ordering::Relaxed);
|
ON_BROKEN_PIPE_FLAG_USED.store(true, crate::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
if let Some(handler) = handler {
|
if let Some(handler) = handler {
|
||||||
rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
|
rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
|
||||||
@ -210,7 +210,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
|
|||||||
target_os = "fuchsia",
|
target_os = "fuchsia",
|
||||||
target_os = "horizon",
|
target_os = "horizon",
|
||||||
)))]
|
)))]
|
||||||
static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
|
static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
|
||||||
crate::sync::atomic::AtomicBool::new(false);
|
crate::sync::atomic::AtomicBool::new(false);
|
||||||
|
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
@ -219,8 +219,8 @@ static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
|
|||||||
target_os = "fuchsia",
|
target_os = "fuchsia",
|
||||||
target_os = "horizon",
|
target_os = "horizon",
|
||||||
)))]
|
)))]
|
||||||
pub(crate) fn unix_sigpipe_attr_specified() -> bool {
|
pub(crate) fn on_broken_pipe_flag_used() -> bool {
|
||||||
UNIX_SIGPIPE_ATTR_SPECIFIED.load(crate::sync::atomic::Ordering::Relaxed)
|
ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: must be called only once during runtime cleanup.
|
// SAFETY: must be called only once during runtime cleanup.
|
||||||
|
@ -353,11 +353,11 @@ impl Command {
|
|||||||
// Inherit the signal mask from the parent rather than resetting it (i.e. do not call
|
// Inherit the signal mask from the parent rather than resetting it (i.e. do not call
|
||||||
// pthread_sigmask).
|
// pthread_sigmask).
|
||||||
|
|
||||||
// If #[unix_sigpipe] is specified, don't reset SIGPIPE to SIG_DFL.
|
// If -Zon-broken-pipe is used, don't reset SIGPIPE to SIG_DFL.
|
||||||
// If #[unix_sigpipe] is not specified, reset SIGPIPE to SIG_DFL for backward compatibility.
|
// If -Zon-broken-pipe is not used, reset SIGPIPE to SIG_DFL for backward compatibility.
|
||||||
//
|
//
|
||||||
// #[unix_sigpipe] is an opportunity to change the default here.
|
// -Zon-broken-pipe is an opportunity to change the default here.
|
||||||
if !crate::sys::pal::unix_sigpipe_attr_specified() {
|
if !crate::sys::pal::on_broken_pipe_flag_used() {
|
||||||
#[cfg(target_os = "android")] // see issue #88585
|
#[cfg(target_os = "android")] // see issue #88585
|
||||||
{
|
{
|
||||||
let mut action: libc::sigaction = mem::zeroed();
|
let mut action: libc::sigaction = mem::zeroed();
|
||||||
@ -450,7 +450,7 @@ impl Command {
|
|||||||
) -> io::Result<Option<Process>> {
|
) -> io::Result<Option<Process>> {
|
||||||
use crate::mem::MaybeUninit;
|
use crate::mem::MaybeUninit;
|
||||||
use crate::sys::weak::weak;
|
use crate::sys::weak::weak;
|
||||||
use crate::sys::{self, cvt_nz, unix_sigpipe_attr_specified};
|
use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
|
||||||
|
|
||||||
if self.get_gid().is_some()
|
if self.get_gid().is_some()
|
||||||
|| self.get_uid().is_some()
|
|| self.get_uid().is_some()
|
||||||
@ -612,11 +612,11 @@ impl Command {
|
|||||||
// Inherit the signal mask from this process rather than resetting it (i.e. do not call
|
// Inherit the signal mask from this process rather than resetting it (i.e. do not call
|
||||||
// posix_spawnattr_setsigmask).
|
// posix_spawnattr_setsigmask).
|
||||||
|
|
||||||
// If #[unix_sigpipe] is specified, don't reset SIGPIPE to SIG_DFL.
|
// If -Zon-broken-pipe is used, don't reset SIGPIPE to SIG_DFL.
|
||||||
// If #[unix_sigpipe] is not specified, reset SIGPIPE to SIG_DFL for backward compatibility.
|
// If -Zon-broken-pipe is not used, reset SIGPIPE to SIG_DFL for backward compatibility.
|
||||||
//
|
//
|
||||||
// #[unix_sigpipe] is an opportunity to change the default here.
|
// -Zon-broken-pipe is an opportunity to change the default here.
|
||||||
if !unix_sigpipe_attr_specified() {
|
if !on_broken_pipe_flag_used() {
|
||||||
let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
|
let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
|
||||||
cvt(sigemptyset(default_set.as_mut_ptr()))?;
|
cvt(sigemptyset(default_set.as_mut_ptr()))?;
|
||||||
cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
|
cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
|
||||||
|
@ -1006,6 +1006,13 @@ pub fn rustc_cargo(
|
|||||||
|
|
||||||
cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)");
|
cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)");
|
||||||
|
|
||||||
|
// If the rustc output is piped to e.g. `head -n1` we want the process to be
|
||||||
|
// killed, rather than having an error bubble up and cause a panic.
|
||||||
|
// FIXME: Synthetic #[cfg(bootstrap)]. Remove when the bootstrap compiler supports it.
|
||||||
|
if compiler.stage != 0 {
|
||||||
|
cargo.rustflag("-Zon-broken-pipe=kill");
|
||||||
|
}
|
||||||
|
|
||||||
// We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary
|
// We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary
|
||||||
// and may just be a time sink.
|
// and may just be a time sink.
|
||||||
if compiler.stage != 0 {
|
if compiler.stage != 0 {
|
||||||
|
@ -471,7 +471,7 @@ impl Step for Rustdoc {
|
|||||||
features.push("jemalloc".to_string());
|
features.push("jemalloc".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let cargo = prepare_tool_cargo(
|
let mut cargo = prepare_tool_cargo(
|
||||||
builder,
|
builder,
|
||||||
build_compiler,
|
build_compiler,
|
||||||
Mode::ToolRustc,
|
Mode::ToolRustc,
|
||||||
@ -482,6 +482,14 @@ impl Step for Rustdoc {
|
|||||||
features.as_slice(),
|
features.as_slice(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If the rustdoc output is piped to e.g. `head -n1` we want the process
|
||||||
|
// to be killed, rather than having an error bubble up and cause a
|
||||||
|
// panic.
|
||||||
|
// FIXME: Synthetic #[cfg(bootstrap)]. Remove when the bootstrap compiler supports it.
|
||||||
|
if build_compiler.stage > 0 {
|
||||||
|
cargo.rustflag("-Zon-broken-pipe=kill");
|
||||||
|
}
|
||||||
|
|
||||||
let _guard = builder.msg_tool(
|
let _guard = builder.msg_tool(
|
||||||
Kind::Build,
|
Kind::Build,
|
||||||
Mode::ToolRustc,
|
Mode::ToolRustc,
|
||||||
|
84
src/doc/unstable-book/src/compiler-flags/on-broken-pipe.md
Normal file
84
src/doc/unstable-book/src/compiler-flags/on-broken-pipe.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# `on-broken-pipe`
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The tracking issue for this feature is: [#97889]
|
||||||
|
|
||||||
|
Note: The ui for this feature was previously an attribute named `#[unix_sigpipe = "..."]`.
|
||||||
|
|
||||||
|
[#97889]: https://github.com/rust-lang/rust/issues/97889
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `-Zon-broken-pipe=...` compiler flag can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This flag is ignored on non-Unix targets. The flag can be used with three different values or be omitted entirely. It affects `SIGPIPE` before `fn main()` and before children get `exec()`'ed:
|
||||||
|
|
||||||
|
| Compiler flag | `SIGPIPE` before `fn main()` | `SIGPIPE` before child `exec()` |
|
||||||
|
|----------------------------|------------------------------|---------------------------------|
|
||||||
|
| not used | `SIG_IGN` | `SIG_DFL` |
|
||||||
|
| `-Zon-broken-pipe=kill` | `SIG_DFL` | not touched |
|
||||||
|
| `-Zon-broken-pipe=error` | `SIG_IGN` | not touched |
|
||||||
|
| `-Zon-broken-pipe=inherit` | not touched | not touched |
|
||||||
|
|
||||||
|
|
||||||
|
## `-Zon-broken-pipe` not used
|
||||||
|
|
||||||
|
If `-Zon-broken-pipe` is not used, libstd will behave in the manner it has since 2014, before Rust 1.0. `SIGPIPE` will be set to `SIG_IGN` before `fn main()` and result in `EPIPE` errors which are converted to `std::io::ErrorKind::BrokenPipe`.
|
||||||
|
|
||||||
|
When spawning child processes, `SIGPIPE` will be set to `SIG_DFL` before doing the underlying `exec()` syscall.
|
||||||
|
|
||||||
|
|
||||||
|
## `-Zon-broken-pipe=kill`
|
||||||
|
|
||||||
|
Set the `SIGPIPE` handler to `SIG_DFL` before invoking `fn main()`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output.
|
||||||
|
|
||||||
|
When spawning child processes, `SIGPIPE` will not be touched. This normally means child processes inherit `SIG_DFL` for `SIGPIPE`.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```rust,no_run
|
||||||
|
fn main() {
|
||||||
|
loop {
|
||||||
|
println!("hello world");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ rustc -Zon-broken-pipe=kill main.rs
|
||||||
|
$ ./main | head -n1
|
||||||
|
hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
## `-Zon-broken-pipe=error`
|
||||||
|
|
||||||
|
Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.
|
||||||
|
|
||||||
|
When spawning child processes, `SIGPIPE` will not be touched. This normally means child processes inherit `SIG_IGN` for `SIGPIPE`.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```rust,no_run
|
||||||
|
fn main() {
|
||||||
|
loop {
|
||||||
|
println!("hello world");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ rustc -Zon-broken-pipe=error main.rs
|
||||||
|
$ ./main | head -n1
|
||||||
|
hello world
|
||||||
|
thread 'main' panicked at library/std/src/io/stdio.rs:1118:9:
|
||||||
|
failed printing to stdout: Broken pipe (os error 32)
|
||||||
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
|
```
|
||||||
|
|
||||||
|
## `-Zon-broken-pipe=inherit`
|
||||||
|
|
||||||
|
Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `-Zon-broken-pipe=kill`.
|
||||||
|
|
||||||
|
When spawning child processes, `SIGPIPE` will not be touched. This normally means child processes inherit `SIG_DFL` for `SIGPIPE`.
|
@ -1,62 +0,0 @@
|
|||||||
# `unix_sigpipe`
|
|
||||||
|
|
||||||
The tracking issue for this feature is: [#97889]
|
|
||||||
|
|
||||||
[#97889]: https://github.com/rust-lang/rust/issues/97889
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
The `#[unix_sigpipe = "..."]` attribute on `fn main()` can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This attribute is ignored on non-Unix targets. There are three variants:
|
|
||||||
* `#[unix_sigpipe = "inherit"]`
|
|
||||||
* `#[unix_sigpipe = "sig_dfl"]`
|
|
||||||
* `#[unix_sigpipe = "sig_ign"]`
|
|
||||||
|
|
||||||
## `#[unix_sigpipe = "inherit"]`
|
|
||||||
|
|
||||||
Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `#[unix_sigpipe = "sig_dfl"]`.
|
|
||||||
|
|
||||||
## `#[unix_sigpipe = "sig_dfl"]`
|
|
||||||
|
|
||||||
Set the `SIGPIPE` handler to `SIG_DFL`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```rust,no_run
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
#[unix_sigpipe = "sig_dfl"]
|
|
||||||
fn main() { loop { println!("hello world"); } }
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
% ./main | head -n 1
|
|
||||||
hello world
|
|
||||||
```
|
|
||||||
|
|
||||||
## `#[unix_sigpipe = "sig_ign"]`
|
|
||||||
|
|
||||||
Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.
|
|
||||||
|
|
||||||
This is what libstd has done by default since 2014. (However, see the note on child processes below.)
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```rust,no_run
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
#[unix_sigpipe = "sig_ign"]
|
|
||||||
fn main() { loop { println!("hello world"); } }
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
% ./main | head -n 1
|
|
||||||
hello world
|
|
||||||
thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9
|
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
||||||
```
|
|
||||||
|
|
||||||
### Note on child processes
|
|
||||||
|
|
||||||
When spawning child processes, the legacy Rust behavior if `#[unix_sigpipe]` is not specified is to
|
|
||||||
reset `SIGPIPE` to `SIG_DFL`.
|
|
||||||
|
|
||||||
If `#[unix_sigpipe = "..."]` is specified, no matter what its value is, the signal disposition of
|
|
||||||
`SIGPIPE` is no longer reset. This means that the child inherits the parent's `SIGPIPE` behavior.
|
|
@ -387,7 +387,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||||||
let main_ptr = ecx.fn_ptr(FnVal::Instance(entry_instance));
|
let main_ptr = ecx.fn_ptr(FnVal::Instance(entry_instance));
|
||||||
|
|
||||||
// Always using DEFAULT is okay since we don't support signals in Miri anyway.
|
// Always using DEFAULT is okay since we don't support signals in Miri anyway.
|
||||||
// (This means we are effectively ignoring `#[unix_sigpipe]`.)
|
// (This means we are effectively ignoring `-Zon-broken-pipe`.)
|
||||||
let sigpipe = rustc_session::config::sigpipe::DEFAULT;
|
let sigpipe = rustc_session::config::sigpipe::DEFAULT;
|
||||||
|
|
||||||
ecx.call_function(
|
ecx.call_function(
|
||||||
|
@ -207,7 +207,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Entry point:
|
// Entry point:
|
||||||
gated!(unix_sigpipe, Normal, template!(Word, NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)),
|
|
||||||
ungated!(start, Normal, template!(Word), WarnFollowing),
|
ungated!(start, Normal, template!(Word), WarnFollowing),
|
||||||
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
|
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
|
||||||
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
|
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_dfl"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
rustdoc::main()
|
rustdoc::main()
|
||||||
}
|
}
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe] //~ error: malformed `unix_sigpipe` attribute input
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: malformed `unix_sigpipe` attribute input
|
|
||||||
--> $DIR/unix_sigpipe-bare.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe]
|
|
||||||
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[unix_sigpipe = "inherit|sig_ign|sig_dfl"]`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
#![unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute cannot be used at crate level
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,17 +0,0 @@
|
|||||||
error: `unix_sigpipe` attribute cannot be used at crate level
|
|
||||||
--> $DIR/unix_sigpipe-crate.rs:2:1
|
|
||||||
|
|
|
||||||
LL | #![unix_sigpipe = "sig_dfl"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
LL |
|
|
||||||
LL | fn main() {}
|
|
||||||
| ---- the inner attribute doesn't annotate this function
|
|
||||||
|
|
|
||||||
help: perhaps you meant to use an outer attribute
|
|
||||||
|
|
|
||||||
LL - #![unix_sigpipe = "sig_dfl"]
|
|
||||||
LL + #[unix_sigpipe = "sig_dfl"]
|
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_ign"]
|
|
||||||
#[unix_sigpipe = "inherit"] //~ error: multiple `unix_sigpipe` attributes
|
|
||||||
fn main() {}
|
|
@ -1,14 +0,0 @@
|
|||||||
error: multiple `unix_sigpipe` attributes
|
|
||||||
--> $DIR/unix_sigpipe-different-duplicates.rs:4:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "inherit"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
|
||||||
|
|
|
||||||
note: attribute also specified here
|
|
||||||
--> $DIR/unix_sigpipe-different-duplicates.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "sig_ign"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "inherit"]
|
|
||||||
#[unix_sigpipe = "inherit"] //~ error: multiple `unix_sigpipe` attributes
|
|
||||||
fn main() {}
|
|
@ -1,14 +0,0 @@
|
|||||||
error: multiple `unix_sigpipe` attributes
|
|
||||||
--> $DIR/unix_sigpipe-duplicates.rs:4:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "inherit"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
|
||||||
|
|
|
||||||
note: attribute also specified here
|
|
||||||
--> $DIR/unix_sigpipe-duplicates.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "inherit"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe(sig_dfl)] //~ error: malformed `unix_sigpipe` attribute input
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: malformed `unix_sigpipe` attribute input
|
|
||||||
--> $DIR/unix_sigpipe-ident-list.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe(sig_dfl)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[unix_sigpipe = "inherit|sig_ign|sig_dfl"]`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
|
|
||||||
fn f() {}
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: `unix_sigpipe` attribute can only be used on `fn main()`
|
|
||||||
--> $DIR/unix_sigpipe-non-main-fn.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "sig_dfl"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
mod m {
|
|
||||||
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on root `fn main()`
|
|
||||||
fn main() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: `unix_sigpipe` attribute can only be used on root `fn main()`
|
|
||||||
--> $DIR/unix_sigpipe-non-root-main.rs:4:5
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "sig_dfl"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
#![feature(start)]
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[start]
|
|
||||||
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
|
|
||||||
fn custom_start(argc: isize, argv: *const *const u8) -> isize { 0 }
|
|
@ -1,8 +0,0 @@
|
|||||||
error: `unix_sigpipe` attribute can only be used on `fn main()`
|
|
||||||
--> $DIR/unix_sigpipe-start.rs:5:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "sig_dfl"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe("sig_dfl")] //~ error: malformed `unix_sigpipe` attribute input
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: malformed `unix_sigpipe` attribute input
|
|
||||||
--> $DIR/unix_sigpipe-str-list.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe("sig_dfl")]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[unix_sigpipe = "inherit|sig_ign|sig_dfl"]`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
|
|
||||||
struct S;
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: `unix_sigpipe` attribute can only be used on `fn main()`
|
|
||||||
--> $DIR/unix_sigpipe-struct.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "sig_dfl"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "wrong"] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
|
|
||||||
--> $DIR/unix_sigpipe-wrong.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "wrong"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
#![crate_type = "bin"]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "inherit"] //~ the `#[unix_sigpipe]` attribute is an experimental feature
|
|
||||||
fn main () {}
|
|
@ -1,13 +0,0 @@
|
|||||||
error[E0658]: the `#[unix_sigpipe]` attribute is an experimental feature
|
|
||||||
--> $DIR/feature-gate-unix_sigpipe.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[unix_sigpipe = "inherit"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: see issue #97889 <https://github.com/rust-lang/rust/issues/97889> for more information
|
|
||||||
= help: add `#![feature(unix_sigpipe)]` to the crate attributes to enable
|
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0658`.
|
|
@ -6,16 +6,14 @@
|
|||||||
//@ ignore-horizon
|
//@ ignore-horizon
|
||||||
//@ ignore-android
|
//@ ignore-android
|
||||||
//@ normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
|
//@ normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
|
||||||
|
//@ compile-flags: -Zon-broken-pipe=error
|
||||||
|
|
||||||
// Test what the error message looks like when `println!()` panics because of
|
// Test what the error message looks like when `println!()` panics because of
|
||||||
// `std::io::ErrorKind::BrokenPipe`
|
// `std::io::ErrorKind::BrokenPipe`
|
||||||
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_ign"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut args = env::args();
|
let mut args = env::args();
|
||||||
let me = args.next().unwrap();
|
let me = args.next().unwrap();
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
//@ aux-crate: sigpipe_utils=sigpipe-utils.rs
|
//@ aux-crate: sigpipe_utils=sigpipe-utils.rs
|
||||||
|
//@ compile-flags: -Zon-broken-pipe=inherit
|
||||||
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "inherit"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
||||||
}
|
}
|
@ -1,8 +1,6 @@
|
|||||||
//@ aux-crate: sigpipe_utils=sigpipe-utils.rs
|
//@ aux-crate: sigpipe_utils=sigpipe-utils.rs
|
||||||
|
//@ compile-flags: -Zon-broken-pipe=inherit
|
||||||
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "inherit"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
||||||
}
|
}
|
@ -1,25 +1,20 @@
|
|||||||
//@ revisions: default sig_dfl sig_ign inherit
|
//@ revisions: default error kill inherit
|
||||||
//@ ignore-cross-compile because aux-bin does not yet support it
|
//@ ignore-cross-compile because aux-bin does not yet support it
|
||||||
//@ only-unix because SIGPIPE is a unix thing
|
//@ only-unix because SIGPIPE is a unix thing
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
//@ aux-bin:assert-sigpipe-disposition.rs
|
//@ aux-bin:assert-sigpipe-disposition.rs
|
||||||
//@ aux-crate:sigpipe_utils=sigpipe-utils.rs
|
//@ aux-crate:sigpipe_utils=sigpipe-utils.rs
|
||||||
|
//@ [kill] compile-flags: -Zunstable-options -Zon-broken-pipe=kill
|
||||||
|
//@ [error] compile-flags: -Zunstable-options -Zon-broken-pipe=error
|
||||||
|
//@ [inherit] compile-flags: -Zunstable-options -Zon-broken-pipe=inherit
|
||||||
|
|
||||||
// Checks the signal disposition of `SIGPIPE` in child processes, and in our own
|
// Checks the signal disposition of `SIGPIPE` in child processes, and in our own
|
||||||
// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is
|
// process for robustness.
|
||||||
// the default. But there is a difference in how `SIGPIPE` is treated in child
|
|
||||||
// processes with and without the attribute. Search for
|
|
||||||
// `unix_sigpipe_attr_specified()` in the code base to learn more.
|
|
||||||
|
|
||||||
#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))]
|
|
||||||
|
|
||||||
extern crate sigpipe_utils;
|
extern crate sigpipe_utils;
|
||||||
|
|
||||||
use sigpipe_utils::*;
|
use sigpipe_utils::*;
|
||||||
|
|
||||||
#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")]
|
|
||||||
#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")]
|
|
||||||
#[cfg_attr(inherit, unix_sigpipe = "inherit")]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// By default we get SIG_IGN but the child gets SIG_DFL through an explicit
|
// By default we get SIG_IGN but the child gets SIG_DFL through an explicit
|
||||||
// reset before exec:
|
// reset before exec:
|
||||||
@ -27,18 +22,18 @@ fn main() {
|
|||||||
#[cfg(default)]
|
#[cfg(default)]
|
||||||
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL");
|
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL");
|
||||||
|
|
||||||
// With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too
|
// We get SIG_DFL and the child does too without any special code running
|
||||||
// without any special code running before exec.
|
// before exec.
|
||||||
#[cfg(sig_dfl)]
|
#[cfg(kill)]
|
||||||
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
|
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
|
||||||
|
|
||||||
// With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too
|
// We get SIG_IGN and the child does too without any special code running
|
||||||
// without any special code running before exec.
|
// before exec.
|
||||||
#[cfg(sig_ign)]
|
#[cfg(error)]
|
||||||
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN");
|
let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN");
|
||||||
|
|
||||||
// With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too
|
// We get SIG_DFL and the child does too without any special code running
|
||||||
// without any special code running before exec.
|
// before exec.
|
||||||
#[cfg(inherit)]
|
#[cfg(inherit)]
|
||||||
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
|
let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL");
|
||||||
|
|
4
tests/ui/runtime/on-broken-pipe/default.rs
Normal file
4
tests/ui/runtime/on-broken-pipe/default.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//@ compile-flags: -Zon-broken-pipe=default
|
||||||
|
//@ check-fail
|
||||||
|
|
||||||
|
fn main() {}
|
2
tests/ui/runtime/on-broken-pipe/default.stderr
Normal file
2
tests/ui/runtime/on-broken-pipe/default.stderr
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
error: incorrect value `default` for unstable option `on-broken-pipe` - either `kill`, `error`, or `inherit` was expected
|
||||||
|
|
@ -1,12 +1,10 @@
|
|||||||
//@ revisions: with_feature without_feature
|
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
//@ aux-build:sigpipe-utils.rs
|
//@ aux-build:sigpipe-utils.rs
|
||||||
|
//@ compile-flags: -Zon-broken-pipe=error
|
||||||
#![cfg_attr(with_feature, feature(unix_sigpipe))]
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
extern crate sigpipe_utils;
|
extern crate sigpipe_utils;
|
||||||
|
|
||||||
// SIGPIPE shall be ignored since #[unix_sigpipe = "..."] is not used
|
// `-Zon-broken-pipe=error` is active, so we expect SIGPIPE to be ignored.
|
||||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
||||||
}
|
}
|
@ -3,20 +3,20 @@
|
|||||||
//@ aux-bin: assert-inherit-sig_dfl.rs
|
//@ aux-bin: assert-inherit-sig_dfl.rs
|
||||||
//@ aux-bin: assert-inherit-sig_ign.rs
|
//@ aux-bin: assert-inherit-sig_ign.rs
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
|
//@ compile-flags: -Zon-broken-pipe=kill
|
||||||
|
|
||||||
#![feature(rustc_private, unix_sigpipe)]
|
#![feature(rustc_private)]
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
// By default the Rust runtime resets SIGPIPE to SIG_DFL before exec'ing child
|
// By default the Rust runtime resets SIGPIPE to SIG_DFL before exec'ing child
|
||||||
// processes so opt-out of that with `#[unix_sigpipe = "sig_dfl"]`. See
|
// processes so opt-out of that with `-Zon-broken-pipe=kill`. See
|
||||||
// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384
|
// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384
|
||||||
#[unix_sigpipe = "sig_dfl"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// First expect SIG_DFL in a child process with #[unix_sigpipe = "inherit"].
|
// First expect SIG_DFL in a child process with -`Zon-broken-pipe=inherit`.
|
||||||
assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl");
|
assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl");
|
||||||
|
|
||||||
// With SIG_IGN we expect #[unix_sigpipe = "inherit"] to also get SIG_IGN.
|
// With SIG_IGN we expect `-Zon-broken-pipe=inherit` to also get SIG_IGN.
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::signal(libc::SIGPIPE, libc::SIG_IGN);
|
libc::signal(libc::SIGPIPE, libc::SIG_IGN);
|
||||||
}
|
}
|
@ -1,13 +1,11 @@
|
|||||||
//@ run-pass
|
//@ run-pass
|
||||||
//@ aux-build:sigpipe-utils.rs
|
//@ aux-build:sigpipe-utils.rs
|
||||||
|
//@ compile-flags: -Zon-broken-pipe=kill
|
||||||
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_dfl"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
extern crate sigpipe_utils;
|
extern crate sigpipe_utils;
|
||||||
|
|
||||||
// #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE shall NOT be ignored, instead
|
// `-Zon-broken-pipe=kill` is active, so SIGPIPE shall NOT be ignored, instead
|
||||||
// the default handler shall be installed
|
// the default handler shall be installed
|
||||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
||||||
}
|
}
|
4
tests/ui/runtime/on-broken-pipe/no-flag-arg.rs
Normal file
4
tests/ui/runtime/on-broken-pipe/no-flag-arg.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//@ compile-flags: -Zon-broken-pipe
|
||||||
|
//@ check-fail
|
||||||
|
|
||||||
|
fn main() {}
|
2
tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr
Normal file
2
tests/ui/runtime/on-broken-pipe/no-flag-arg.stderr
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
error: unstable option `on-broken-pipe` requires either `kill`, `error`, or `inherit` (Z on-broken-pipe=<value>)
|
||||||
|
|
@ -1,13 +1,9 @@
|
|||||||
//@ run-pass
|
//@ run-pass
|
||||||
//@ aux-build:sigpipe-utils.rs
|
//@ aux-build:sigpipe-utils.rs
|
||||||
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_ign"]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
extern crate sigpipe_utils;
|
extern crate sigpipe_utils;
|
||||||
|
|
||||||
// #[unix_sigpipe = "sig_ign"] is active, so the legacy behavior of ignoring
|
// SIGPIPE shall be ignored since `-Zon-broken-pipe` is not used
|
||||||
// SIGPIPE shall be in effect
|
|
||||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
|
||||||
}
|
}
|
@ -1,15 +1,14 @@
|
|||||||
//@ run-pass
|
//@ run-pass
|
||||||
//@ aux-build:sigpipe-utils.rs
|
//@ aux-build:sigpipe-utils.rs
|
||||||
|
//@ compile-flags: -Zon-broken-pipe=kill
|
||||||
|
|
||||||
#![feature(unix_sigpipe)]
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[unix_sigpipe = "sig_dfl"]
|
|
||||||
#[rustc_main]
|
#[rustc_main]
|
||||||
fn rustc_main() {
|
fn rustc_main() {
|
||||||
extern crate sigpipe_utils;
|
extern crate sigpipe_utils;
|
||||||
|
|
||||||
// #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE handler shall be
|
// `-Zon-broken-pipe=kill` is active, so SIGPIPE handler shall be
|
||||||
// SIG_DFL. Note that we have a #[rustc_main], but it should still work.
|
// SIG_DFL. Note that we have a #[rustc_main], but it should still work.
|
||||||
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
|
||||||
}
|
}
|
4
tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs
Normal file
4
tests/ui/runtime/on-broken-pipe/wrong-flag-arg.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//@ compile-flags: -Zon-broken-pipe=wrong
|
||||||
|
//@ check-fail
|
||||||
|
|
||||||
|
fn main() {}
|
2
tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr
Normal file
2
tests/ui/runtime/on-broken-pipe/wrong-flag-arg.stderr
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
error: incorrect value `wrong` for unstable option `on-broken-pipe` - either `kill`, `error`, or `inherit` was expected
|
||||||
|
|
Loading…
Reference in New Issue
Block a user