about summary refs log tree commit diff
path: root/src/tools/miri
diff options
context:
space:
mode:
authorThe Miri Conjob Bot <miri@cron.bot>2023-08-31 05:40:49 +0000
committerThe Miri Conjob Bot <miri@cron.bot>2023-08-31 05:40:49 +0000
commit31d9ac14f52c88fbec16a12787e23a7f5ba671cf (patch)
tree6a886a36309aecfd5d3712a24e51bc28f8197917 /src/tools/miri
parent4b915b8a86df64e6758b6cc329d83d5fe635f21d (diff)
parent8cbd2c847b682a3ce460a79fa7576ee2eb461a00 (diff)
downloadrust-31d9ac14f52c88fbec16a12787e23a7f5ba671cf.tar.gz
rust-31d9ac14f52c88fbec16a12787e23a7f5ba671cf.zip
Merge from rustc
Diffstat (limited to 'src/tools/miri')
-rw-r--r--src/tools/miri/src/diagnostics.rs67
-rw-r--r--src/tools/miri/src/helpers.rs23
-rw-r--r--src/tools/miri/tests/fail/type-too-large.rs2
-rw-r--r--src/tools/miri/tests/fail/unsized-local.stderr2
-rw-r--r--src/tools/miri/tests/pass/unsized.rs24
5 files changed, 64 insertions, 54 deletions
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index f3285ccf917..75c6911bcbe 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -1,9 +1,8 @@
-use std::fmt;
+use std::fmt::{self, Write};
 use std::num::NonZeroU64;
 
 use log::trace;
 
-use rustc_const_eval::ReportErrorExt;
 use rustc_errors::DiagnosticMessage;
 use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
 use rustc_target::abi::{Align, Size};
@@ -271,17 +270,20 @@ pub fn report_error<'tcx, 'mir>(
         };
         (title, helps)
     } else {
-        #[rustfmt::skip]
         let title = match e.kind() {
-            UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(e)) if matches!(e.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
-                bug!("This validation error should be impossible in Miri: {:?}", e.kind),
+            UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err))
+                if matches!(validation_err.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
+            {
+                ecx.handle_ice(); // print interpreter backtrace
+                bug!("This validation error should be impossible in Miri: {}", ecx.format_error(e));
+            }
             UndefinedBehavior(_) =>
                 "Undefined Behavior",
             ResourceExhaustion(_) =>
                 "resource exhaustion",
             Unsupported(
                 // We list only the ones that can actually happen.
-                UnsupportedOpInfo::Unsupported(_)
+                UnsupportedOpInfo::Unsupported(_) | UnsupportedOpInfo::UnsizedLocal
             ) =>
                 "unsupported operation",
             InvalidProgram(
@@ -290,8 +292,10 @@ pub fn report_error<'tcx, 'mir>(
                 InvalidProgramInfo::Layout(..)
             ) =>
                 "post-monomorphization error",
-            kind =>
-                bug!("This error should be impossible in Miri: {kind:?}"),
+            _ => {
+                ecx.handle_ice(); // print interpreter backtrace
+                bug!("This error should be impossible in Miri: {}", ecx.format_error(e));
+            }
         };
         #[rustfmt::skip]
         let helps = match e.kind() {
@@ -333,30 +337,22 @@ pub fn report_error<'tcx, 'mir>(
 
     let stacktrace = ecx.generate_stacktrace();
     let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
-    let (e, backtrace) = e.into_parts();
-    backtrace.print_backtrace();
-
-    // We want to dump the allocation if this is `InvalidUninitBytes`. Since `add_args` consumes
-    // the `InterpError`, we extract the variables it before that.
-    let extra = match e {
-        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) =>
-            Some((alloc_id, access)),
-        _ => None,
-    };
 
-    // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
-    // label and arguments from the InterpError.
-    let e = {
-        let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
-        let mut diag = ecx.tcx.sess.struct_allow("");
-        let msg = e.diagnostic_message();
-        e.add_args(handler, &mut diag);
-        let s = handler.eagerly_translate_to_string(msg, diag.args());
-        diag.cancel();
-        s
-    };
+    // We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
+    let mut extra = String::new();
+    match e.kind() {
+        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
+            writeln!(
+                extra,
+                "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
+                range = access.bad,
+            ).unwrap();
+            writeln!(extra, "{:?}", ecx.dump_alloc(*alloc_id)).unwrap();
+        }
+        _ => {}
+    }
 
-    msg.insert(0, e);
+    msg.insert(0, ecx.format_error(e));
 
     report_msg(
         DiagLevel::Error,
@@ -375,6 +371,8 @@ pub fn report_error<'tcx, 'mir>(
         );
     }
 
+    eprint!("{extra}"); // newlines are already in the string
+
     // Debug-dump all locals.
     for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
         trace!("-------------------");
@@ -385,15 +383,6 @@ pub fn report_error<'tcx, 'mir>(
         }
     }
 
-    // Extra output to help debug specific issues.
-    if let Some((alloc_id, access)) = extra {
-        eprintln!(
-            "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
-            range = access.bad,
-        );
-        eprintln!("{:?}", ecx.dump_alloc(alloc_id));
-    }
-
     None
 }
 
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index b5cc5c7e486..844827889a7 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -14,7 +14,7 @@ use rustc_middle::mir;
 use rustc_middle::ty::{
     self,
     layout::{IntegerExt as _, LayoutOf, TyAndLayout},
-    List, Ty, TyCtxt,
+    Ty, TyCtxt,
 };
 use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
 use rustc_target::abi::{Align, FieldIdx, FieldsShape, Integer, Size, Variants};
@@ -282,13 +282,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         Ok(ptr.addr().bytes() == 0)
     }
 
-    /// Get the `Place` for a local
-    fn local_place(&self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> {
-        let this = self.eval_context_ref();
-        let place = mir::Place { local, projection: List::empty() };
-        this.eval_place(place)
-    }
-
     /// Generate some random bytes, and write them to `dest`.
     fn gen_random(&mut self, ptr: Pointer<Option<Provenance>>, len: u64) -> InterpResult<'tcx> {
         // Some programs pass in a null pointer and a length of 0
@@ -350,17 +343,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         // Initialize arguments.
         let mut callee_args = this.frame().body.args_iter();
         for arg in args {
-            let callee_arg = this.local_place(
-                callee_args
-                    .next()
-                    .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?,
-            )?;
+            let local = callee_args
+                .next()
+                .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?;
+            // Make the local live, and insert the initial value.
+            this.storage_live(local)?;
+            let callee_arg = this.local_to_place(this.frame_idx(), local)?;
             this.write_immediate(*arg, &callee_arg)?;
         }
         if callee_args.next().is_some() {
             throw_ub_format!("callee has more arguments than expected");
         }
 
+        // Initialize remaining locals.
+        this.storage_live_for_always_live_locals()?;
+
         Ok(())
     }
 
diff --git a/src/tools/miri/tests/fail/type-too-large.rs b/src/tools/miri/tests/fail/type-too-large.rs
index 21b272f8ec3..81ecc6145d7 100644
--- a/src/tools/miri/tests/fail/type-too-large.rs
+++ b/src/tools/miri/tests/fail/type-too-large.rs
@@ -1,6 +1,6 @@
 //@ignore-32bit
 
 fn main() {
-    let _fat: [u8; (1 << 61) + (1 << 31)];
+    let _fat: [u8; (1 << 61) + (1 << 31)]; // ideally we'd error here, but we avoid computing the layout until absolutely necessary
     _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR: post-monomorphization error
 }
diff --git a/src/tools/miri/tests/fail/unsized-local.stderr b/src/tools/miri/tests/fail/unsized-local.stderr
index 66d93c6f503..07f94f3b91b 100644
--- a/src/tools/miri/tests/fail/unsized-local.stderr
+++ b/src/tools/miri/tests/fail/unsized-local.stderr
@@ -2,7 +2,7 @@ error: unsupported operation: unsized locals are not supported
   --> $DIR/unsized-local.rs:LL:CC
    |
 LL |     let x = *(Box::new(A) as Box<dyn Foo>);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsized locals are not supported
+   |         ^ unsized locals are not supported
    |
    = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/pass/unsized.rs b/src/tools/miri/tests/pass/unsized.rs
index c9046dc3c76..5c6929882f6 100644
--- a/src/tools/miri/tests/pass/unsized.rs
+++ b/src/tools/miri/tests/pass/unsized.rs
@@ -2,6 +2,7 @@
 //@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(unsized_tuple_coercion)]
 #![feature(unsized_fn_params)]
+#![feature(custom_mir, core_intrinsics)]
 
 use std::mem;
 
@@ -32,7 +33,30 @@ fn unsized_params() {
     f3(*p);
 }
 
+fn unsized_field_projection() {
+    use std::intrinsics::mir::*;
+
+    pub struct S<T: ?Sized>(T);
+
+    #[custom_mir(dialect = "runtime", phase = "optimized")]
+    fn f(x: S<[u8]>) {
+        mir! {
+            {
+                let idx = 0;
+                // Project to an unsized field of an unsized local.
+                x.0[idx] = 0;
+                let _val = x.0[idx];
+                Return()
+            }
+        }
+    }
+
+    let x: Box<S<[u8]>> = Box::new(S([0]));
+    f(*x);
+}
+
 fn main() {
     unsized_tuple();
     unsized_params();
+    unsized_field_projection();
 }