use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
use rustc_target::abi::{Align, Size};
-use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind};
+use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory;
use crate::*;
/// Details of premature program termination.
pub enum TerminationInfo {
- Exit(i64),
+ Exit {
+ code: i64,
+ leak_check: bool,
+ },
Abort(String),
UnsupportedInIsolation(String),
StackedBorrowsUb {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use TerminationInfo::*;
match self {
- Exit(code) => write!(f, "the evaluated program completed with exit code {code}"),
+ Exit { code, .. } => write!(f, "the evaluated program completed with exit code {code}"),
Abort(msg) => write!(f, "{msg}"),
UnsupportedInIsolation(msg) => write!(f, "{msg}"),
Int2PtrWithStrictProvenance =>
///
/// new_kind is `None` for base tags.
CreatedPointerTag(NonZeroU64, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>),
- /// This `Item` was popped from the borrow stack, either due to an access with the given tag or
- /// a deallocation when the second argument is `None`.
- PoppedPointerTag(Item, Option<(ProvenanceExtra, AccessKind)>),
+ /// This `Item` was popped from the borrow stack. The string explains the reason.
+ PoppedPointerTag(Item, String),
CreatedCallId(CallId),
CreatedAlloc(AllocId, Size, Align, MemoryKind<MiriMemoryKind>),
FreedAlloc(AllocId),
}
}
-/// Emit a custom diagnostic without going through the miri-engine machinery
+/// Emit a custom diagnostic without going through the miri-engine machinery.
+///
+/// Returns `Some` if this was regular program termination with a given exit code and a `bool` indicating whether a leak check should happen; `None` otherwise.
pub fn report_error<'tcx, 'mir>(
ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
e: InterpErrorInfo<'tcx>,
-) -> Option<i64> {
+) -> Option<(i64, bool)> {
use InterpError::*;
let mut msg = vec![];
- let (title, helps) = match &e.kind() {
- MachineStop(info) => {
- let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
- use TerminationInfo::*;
- let title = match info {
- Exit(code) => return Some(*code),
- Abort(_) => Some("abnormal termination"),
- UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance =>
- Some("unsupported operation"),
- StackedBorrowsUb { .. } => Some("Undefined Behavior"),
- Deadlock => Some("deadlock"),
- MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
- };
- #[rustfmt::skip]
- let helps = match info {
- UnsupportedInIsolation(_) =>
- vec![
- (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
- (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
- ],
- StackedBorrowsUb { help, history, .. } => {
- let url = "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md";
- msg.extend(help.clone());
- let mut helps = vec![
- (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")),
- (None, format!("see {url} for further information")),
- ];
- if let Some(TagHistory {created, invalidated, protected}) = history.clone() {
- helps.push((Some(created.1), created.0));
- if let Some((msg, span)) = invalidated {
- helps.push((Some(span), msg));
- }
- if let Some((protector_msg, protector_span)) = protected {
- helps.push((Some(protector_span), protector_msg));
- }
+ let (title, helps) = if let MachineStop(info) = e.kind() {
+ let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
+ use TerminationInfo::*;
+ let title = match info {
+ Exit { code, leak_check } => return Some((*code, *leak_check)),
+ Abort(_) => Some("abnormal termination"),
+ UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance =>
+ Some("unsupported operation"),
+ StackedBorrowsUb { .. } => Some("Undefined Behavior"),
+ Deadlock => Some("deadlock"),
+ MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
+ };
+ #[rustfmt::skip]
+ let helps = match info {
+ UnsupportedInIsolation(_) =>
+ vec![
+ (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
+ (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
+ ],
+ StackedBorrowsUb { help, history, .. } => {
+ let url = "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md";
+ msg.extend(help.clone());
+ let mut helps = vec![
+ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")),
+ (None, format!("see {url} for further information")),
+ ];
+ if let Some(TagHistory {created, invalidated, protected}) = history.clone() {
+ helps.push((Some(created.1), created.0));
+ if let Some((msg, span)) = invalidated {
+ helps.push((Some(span), msg));
+ }
+ if let Some((protector_msg, protector_span)) = protected {
+ helps.push((Some(protector_span), protector_msg));
}
- helps
}
- MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
- vec![
- (Some(*first), format!("it's first defined here, in crate `{first_crate}`")),
- (Some(*second), format!("then it's defined here again, in crate `{second_crate}`")),
- ],
- SymbolShimClashing { link_name, span } =>
- vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))],
- Int2PtrWithStrictProvenance =>
- vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))],
- _ => vec![],
- };
- (title, helps)
- }
- _ => {
- #[rustfmt::skip]
- let title = match e.kind() {
- Unsupported(_) =>
- "unsupported operation",
- UndefinedBehavior(_) =>
- "Undefined Behavior",
- ResourceExhaustion(_) =>
- "resource exhaustion",
- InvalidProgram(
- InvalidProgramInfo::AlreadyReported(_) |
- InvalidProgramInfo::Layout(..) |
- InvalidProgramInfo::ReferencedConstant
- ) =>
- "post-monomorphization error",
- kind =>
- bug!("This error should be impossible in Miri: {kind:?}"),
- };
- #[rustfmt::skip]
- let helps = match e.kind() {
- Unsupported(
- UnsupportedOpInfo::ThreadLocalStatic(_) |
- UnsupportedOpInfo::ReadExternStatic(_) |
- UnsupportedOpInfo::PartialPointerOverwrite(_) | // we make memory uninit instead
- UnsupportedOpInfo::ReadPointerAsBytes
- ) =>
- panic!("Error should never be raised by Miri: {kind:?}", kind = e.kind()),
- Unsupported(
- UnsupportedOpInfo::Unsupported(_) |
- UnsupportedOpInfo::PartialPointerCopy(_)
- ) =>
- vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
- UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
- if ecx.machine.check_alignment == AlignmentCheck::Symbolic
- =>
- vec![
- (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
- (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
- ],
- UndefinedBehavior(_) =>
- vec![
- (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
- (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
- ],
- InvalidProgram(_) | ResourceExhaustion(_) | MachineStop(_) =>
- vec![],
- };
- (Some(title), helps)
- }
+ helps
+ }
+ MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
+ vec![
+ (Some(*first), format!("it's first defined here, in crate `{first_crate}`")),
+ (Some(*second), format!("then it's defined here again, in crate `{second_crate}`")),
+ ],
+ SymbolShimClashing { link_name, span } =>
+ vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))],
+ Int2PtrWithStrictProvenance =>
+ vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))],
+ _ => vec![],
+ };
+ (title, helps)
+ } else {
+ #[rustfmt::skip]
+ let title = match e.kind() {
+ UndefinedBehavior(_) =>
+ "Undefined Behavior",
+ ResourceExhaustion(_) =>
+ "resource exhaustion",
+ Unsupported(
+ // We list only the ones that can actually happen.
+ UnsupportedOpInfo::Unsupported(_)
+ ) =>
+ "unsupported operation",
+ InvalidProgram(
+ // We list only the ones that can actually happen.
+ InvalidProgramInfo::AlreadyReported(_) |
+ InvalidProgramInfo::Layout(..)
+ ) =>
+ "post-monomorphization error",
+ kind =>
+ bug!("This error should be impossible in Miri: {kind:?}"),
+ };
+ #[rustfmt::skip]
+ let helps = match e.kind() {
+ Unsupported(_) =>
+ vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
+ UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
+ if ecx.machine.check_alignment == AlignmentCheck::Symbolic
+ =>
+ vec![
+ (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
+ (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
+ ],
+ UndefinedBehavior(_) =>
+ vec![
+ (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
+ (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
+ ],
+ InvalidProgram(
+ InvalidProgramInfo::AlreadyReported(rustc_errors::ErrorGuaranteed { .. })
+ ) => {
+ // This got already reported. No point in reporting it again.
+ return None;
+ }
+ _ =>
+ vec![],
+ };
+ (Some(title), helps)
};
let stacktrace = ecx.generate_stacktrace();
format!(
"created tag {tag:?} for {kind} at {alloc_id:?}{range:?} derived from {orig_tag:?}"
),
- PoppedPointerTag(item, tag) =>
- match tag {
- None => format!("popped tracked tag for item {item:?} due to deallocation",),
- Some((tag, access)) => {
- format!(
- "popped tracked tag for item {item:?} due to {access:?} access for {tag:?}",
- )
- }
- },
+ PoppedPointerTag(item, cause) => format!("popped tracked tag for item {item:?}{cause}"),
CreatedCallId(id) => format!("function call with id {id}"),
CreatedAlloc(AllocId(id), size, align, kind) =>
format!(