about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-09 13:37:41 +0000
committerbors <bors@rust-lang.org>2023-07-09 13:37:41 +0000
commitb12ff66f2c9daf6538fe0548b3c2ba16d9185cfb (patch)
treec97af39bcea17f03de06e70ad8f0f55d0b931dc5 /src
parentba37a69d30fc6ffc0c2589eb59e936c261b36e76 (diff)
parent9ed46696804befa494620831a485fe3d3deffa24 (diff)
downloadrust-b12ff66f2c9daf6538fe0548b3c2ba16d9185cfb.tar.gz
rust-b12ff66f2c9daf6538fe0548b3c2ba16d9185cfb.zip
Auto merge of #113488 - RalfJung:miri, r=RalfJung
update Miri
Diffstat (limited to 'src')
-rw-r--r--src/tools/miri/.github/workflows/ci.yml47
-rw-r--r--src/tools/miri/Cargo.lock4
-rw-r--r--src/tools/miri/Cargo.toml2
-rw-r--r--src/tools/miri/cargo-miri/src/main.rs6
-rw-r--r--src/tools/miri/cargo-miri/src/util.rs4
-rwxr-xr-xsrc/tools/miri/miri3
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs29
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs9
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs26
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs8
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs6
-rw-r--r--src/tools/miri/src/eval.rs21
-rw-r--r--src/tools/miri/src/lib.rs1
-rw-r--r--src/tools/miri/src/machine.rs8
-rw-r--r--src/tools/miri/src/shims/backtrace.rs2
-rw-r--r--src/tools/miri/src/shims/env.rs10
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs6
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs14
-rw-r--r--src/tools/miri/src/shims/os_str.rs6
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd.rs1
-rw-r--r--src/tools/miri/tests/compiletest.rs17
-rw-r--r--src/tools/miri/tests/fail/shims/memchr_null.rs10
-rw-r--r--src/tools/miri/tests/fail/shims/memchr_null.stderr15
-rw-r--r--src/tools/miri/tests/fail/shims/memcmp_null.rs10
-rw-r--r--src/tools/miri/tests/fail/shims/memcmp_null.stderr15
-rw-r--r--src/tools/miri/tests/fail/shims/memcpy_zero.rs12
-rw-r--r--src/tools/miri/tests/fail/shims/memcpy_zero.stderr15
-rw-r--r--src/tools/miri/tests/fail/shims/memrchr_null.rs11
-rw-r--r--src/tools/miri/tests/fail/shims/memrchr_null.stderr15
-rw-r--r--src/tools/miri/tests/pass/vec.rs12
32 files changed, 251 insertions, 98 deletions
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 8068db1cf4f..c87b3e42323 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -15,6 +15,10 @@ on:
 env:
   CARGO_UNSTABLE_SPARSE_REGISTRY: 'true'
 
+defaults:
+  run:
+    shell: bash
+
 jobs:
   build:
     runs-on: ${{ matrix.os }}
@@ -59,12 +63,9 @@ jobs:
 
       - name: Install rustup-toolchain-install-master
         if: ${{ steps.cache.outputs.cache-hit != 'true' }}
-        shell: bash
-        run: |
-          cargo install -f rustup-toolchain-install-master
+        run: cargo install -f rustup-toolchain-install-master
 
       - name: Install "master" toolchain
-        shell: bash
         run: |
           if [[ ${{ github.event_name }} == 'schedule' ]]; then
             echo "Building against latest rustc git version"
@@ -79,7 +80,7 @@ jobs:
           cargo -V
 
       - name: Test
-        run: bash ./ci.sh
+        run: ./ci.sh
 
   style:
     name: style checks
@@ -111,14 +112,10 @@ jobs:
 
       - name: Install rustup-toolchain-install-master
         if: ${{ steps.cache.outputs.cache-hit != 'true' }}
-        shell: bash
-        run: |
-          cargo install -f rustup-toolchain-install-master
+        run: cargo install -f rustup-toolchain-install-master
 
       - name: Install "master" toolchain
-        shell: bash
-        run: |
-          ./miri toolchain
+        run: ./miri toolchain
 
       - name: Show Rust version
         run: |
@@ -138,7 +135,6 @@ jobs:
   # workflow is successful listening to webhooks only.
   #
   # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
-  # (`fmt` is deliberately not listed, we want bors to ignore it.)
   end-success:
     name: bors build finished
     runs-on: ubuntu-latest
@@ -166,12 +162,12 @@ jobs:
       - name: Install zulip-send
         run: pip3 install zulip
       - name: Send Zulip notification
-        shell: bash
         env:
           ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
           ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
         run: |
-          ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
+          ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
+            --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
             --message 'Dear @*T-miri*,
 
           It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed.
@@ -183,9 +179,12 @@ jobs:
 
           Thanks in advance!
           Sincerely,
-          The Miri Cronjobs Bot' \
-            --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com
+          The Miri Cronjobs Bot'
+
       # Attempt to auto-sync with rustc
+      - uses: actions/checkout@v3
+        with:
+          fetch-depth: 256 # get a bit more of the history
       - name: install josh-proxy
         run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06
       - name: start josh-proxy
@@ -196,16 +195,24 @@ jobs:
           git config --global user.email 'miri@cron.bot'
       - name: get changes from rustc
         run: ./miri rustc-pull
+      - name: Install rustup-toolchain-install-master
+        run: cargo install -f rustup-toolchain-install-master
       - name: format changes (if any)
         run: |
           ./miri toolchain
           ./miri fmt --check || (./miri fmt && git commit -am "fmt")
       - name: Push changes to a branch
         run: |
-          git switch -c "rustup$(date -u +%Y-%m)"
-          git push
+          BRANCH="rustup$(date -u +%Y-%m-%d)"
+          git switch -c $BRANCH
+          git push -u origin $BRANCH
       - name: Create Pull Request
-        run: gh pr create -B master --title 'Automatic sync from rustc' --body ''
+        run: |
+          PR=$(gh pr create -B master --title 'Automatic sync from rustc' --body '')
+          ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
+            --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
+            --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
+          ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
+          ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index edb3ee48a4e..4232d7fda78 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -842,9 +842,9 @@ dependencies = [
 
 [[package]]
 name = "ui_test"
-version = "0.11.6"
+version = "0.11.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24a2e70adc9d18b9b4dd80ea57aeec447103c6fbb354a07c080adad451c645e1"
+checksum = "c21899b59f53717dfad29e4f46e5b21a200a1b6888ab86532a07cfc8b48dd78c"
 dependencies = [
  "bstr",
  "cargo-platform",
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 50864334fc5..a625e1696e1 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -36,7 +36,7 @@ libloading = "0.7"
 
 [dev-dependencies]
 colored = "2"
-ui_test = "0.11.6"
+ui_test = "0.11.7"
 rustc_version = "0.4"
 # Features chosen to match those required by env_logger, to avoid rebuilds
 regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] }
diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs
index 85c9cdad7df..6178670b4f0 100644
--- a/src/tools/miri/cargo-miri/src/main.rs
+++ b/src/tools/miri/cargo-miri/src/main.rs
@@ -80,7 +80,11 @@ fn main() {
     match first.as_str() {
         "miri" => phase_cargo_miri(args),
         "runner" => phase_runner(args, RunnerPhase::Cargo),
-        arg if arg == env::var("RUSTC").unwrap() => {
+        arg if arg == env::var("RUSTC").unwrap_or_else(|_| {
+            show_error!(
+                "`cargo-miri` called without RUSTC set; please only invoke this binary through `cargo miri`"
+            )
+        }) => {
             // If the first arg is equal to the RUSTC env variable (which should be set at this
             // point), then we need to behave as rustc. This is the somewhat counter-intuitive
             // behavior of having both RUSTC and RUSTC_WRAPPER set
diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs
index 60f39cb36ab..4c19ed97fb8 100644
--- a/src/tools/miri/cargo-miri/src/util.rs
+++ b/src/tools/miri/cargo-miri/src/util.rs
@@ -82,7 +82,7 @@ pub enum MiriCommand {
 pub fn escape_for_toml(s: &str) -> String {
     // We want to surround this string in quotes `"`. So we first escape all quotes,
     // and also all backslashes (that are used to escape quotes).
-    let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#);
+    let s = s.replace('\\', r"\\").replace('"', r#"\""#);
     format!("\"{s}\"")
 }
 
@@ -130,7 +130,7 @@ pub fn exec(mut cmd: Command) -> ! {
     {
         use std::os::unix::process::CommandExt;
         let error = cmd.exec();
-        Err(error).expect("failed to run command")
+        panic!("failed to run command: {error}")
     }
 }
 
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index 7cda995879c..ace3d17ae2a 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -124,7 +124,7 @@ rustc-pull)
     git commit rust-version -m "Preparing for merge from rustc" || (echo "FAILED to commit rust-version file, something went wrong"; exit 1)
     # Fetch given rustc commit and note down which one that was
     git fetch http://localhost:8000/rust-lang/rust.git@$FETCH_COMMIT$JOSH_FILTER.git || (echo "FAILED to fetch new commits, something went wrong"; exit 1)
-    git merge FETCH_HEAD --no-ff -m "Merge from rustc" || (echo "FAILED to merge new commits, something went wrong"; exit 1)
+    git merge FETCH_HEAD --no-ff -m "Merge from rustc" || (echo "FAILED to merge new commits ($(git rev-parse FETCH_HEAD)), something went wrong"; exit 1)
     exit 0
     ;;
 rustc-push)
@@ -325,6 +325,7 @@ run|run-dep)
         MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET"
     fi
 
+    CARGO="$CARGO --quiet"
     # First build and get a sysroot.
     $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
     find_sysroot
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 6790454bdb7..02b0dd16f91 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-75726cae37317c7262b69d3e9fd11a3496a88d04
+d4096e0412ac5de785d739a0aa2b1c1c7b9d3b7d
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 2dc33334417..1ec4cbc4de7 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -67,7 +67,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             if tcx.sess.compile_status().is_err() {
                 tcx.sess.fatal("miri cannot be run on programs that fail compilation");
             }
-;
+
             init_late_loggers(handler, tcx);
             if !tcx.sess.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index c9674e0a2fe..de307a3c5f5 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -221,7 +221,10 @@ impl AllocHistory {
 impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
     pub fn start_grant(&mut self, perm: Permission) {
         let Operation::Retag(op) = &mut self.operation else {
-            unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation)
+            unreachable!(
+                "start_grant must only be called during a retag, this is: {:?}",
+                self.operation
+            )
         };
         op.permission = Some(perm);
 
@@ -286,7 +289,8 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
         tag: BorTag,
         protector_tag: Option<BorTag>,
     ) -> Option<TagHistory> {
-        let Some(created) = self.history
+        let Some(created) = self
+            .history
             .creations
             .iter()
             .rev()
@@ -315,22 +319,27 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
                         None
                     }
                 })
-            }).or_else(|| {
+            })
+            .or_else(|| {
                 // If we didn't find a retag that created this tag, it might be the base tag of
                 // this allocation.
                 if self.history.base.0.tag() == tag {
                     Some((
-                        format!("{tag:?} was created here, as the base tag for {:?}", self.history.id),
-                        self.history.base.1.data()
+                        format!(
+                            "{tag:?} was created here, as the base tag for {:?}",
+                            self.history.id
+                        ),
+                        self.history.base.1.data(),
                     ))
                 } else {
                     None
                 }
-            }) else {
-                // But if we don't have a creation event, this is related to a wildcard, and there
-                // is really nothing we can do to help.
-                return None;
-            };
+            })
+        else {
+            // But if we don't have a creation event, this is related to a wildcard, and there
+            // is really nothing we can do to help.
+            return None;
+        };
 
         let invalidated = self.history.invalidations.iter().rev().find_map(|event| {
             if event.tag == tag { Some(event.generate_diagnostic()) } else { None }
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 581327e54f1..ca0f69450c9 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -430,12 +430,15 @@ impl<'tcx> Stack {
                 .find_granting(AccessKind::Write, derived_from, exposed_tags)
                 .map_err(|()| dcx.grant_error(self))?;
 
-            let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else {
+            let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from)
+            else {
                 // The parent is a wildcard pointer or matched the unknown bottom.
                 // This is approximate. Nobody knows what happened, so forget everything.
                 // The new thing is SRW anyway, so we cannot push it "on top of the unknown part"
                 // (for all we know, it might join an SRW group inside the unknown).
-                trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown");
+                trace!(
+                    "reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"
+                );
                 self.set_unknown_bottom(global.next_ptr_tag);
                 return Ok(());
             };
@@ -1008,7 +1011,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // We have to turn the place into a pointer to use the existing code.
         // (The pointer type does not matter, so we use a raw pointer.)
-        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?;
+        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?;
         let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
         // Reborrow it. With protection! That is part of the point.
         let new_perm = NewPermission::Uniform {
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
index a1e949183ad..291807c25ee 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
@@ -196,19 +196,19 @@ impl<'tcx> Stack {
         let ProvenanceExtra::Concrete(tag) = tag else {
             // Handle the wildcard case.
             // Go search the stack for an exposed tag.
-            if let Some(idx) =
-                self.borrows
-                    .iter()
-                    .enumerate() // we also need to know *where* in the stack
-                    .rev() // search top-to-bottom
-                    .find_map(|(idx, item)| {
-                        // If the item fits and *might* be this wildcard, use it.
-                        if item.perm().grants(access) && exposed_tags.contains(&item.tag()) {
-                            Some(idx)
-                        } else {
-                            None
-                        }
-                    })
+            if let Some(idx) = self
+                .borrows
+                .iter()
+                .enumerate() // we also need to know *where* in the stack
+                .rev() // search top-to-bottom
+                .find_map(|(idx, item)| {
+                    // If the item fits and *might* be this wildcard, use it.
+                    if item.perm().grants(access) && exposed_tags.contains(&item.tag()) {
+                        Some(idx)
+                    } else {
+                        None
+                    }
+                })
             {
                 return Ok(Some(idx));
             }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index a87a4bbddad..3b2d6f9608e 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -570,9 +570,13 @@ impl DisplayRepr {
         extraction_aux(tree, tree.root, show_unnamed, &mut v);
         let Some(root) = v.pop() else {
             if show_unnamed {
-                unreachable!("This allocation contains no tags, not even a root. This should not happen.");
+                unreachable!(
+                    "This allocation contains no tags, not even a root. This should not happen."
+                );
             }
-            eprintln!("This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags.");
+            eprintln!(
+                "This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."
+            );
             return None;
         };
         assert!(v.is_empty());
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 4c0690c585c..e134b739888 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -256,7 +256,9 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
             ptr_size.bytes()
         );
 
-        let Some(new_perm) = new_perm else { return Ok(Some((alloc_id, orig_tag))); };
+        let Some(new_perm) = new_perm else {
+            return Ok(Some((alloc_id, orig_tag)));
+        };
 
         if let Some(protect) = new_perm.protector {
             // We register the protection in two different places.
@@ -509,7 +511,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // We have to turn the place into a pointer to use the existing code.
         // (The pointer type does not matter, so we use a raw pointer.)
-        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?;
+        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?;
         let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
         // Reborrow it. With protection! That is part of the point.
         // FIXME: do we truly want a 2phase borrow here?
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 56de9c007d0..aba7dd5a9fe 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -305,7 +305,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
         for arg in config.args.iter() {
             // Make space for `0` terminator.
             let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap();
-            let arg_type = Ty::new_array(tcx,tcx.types.u8, size);
+            let arg_type = Ty::new_array(tcx, tcx.types.u8, size);
             let arg_place =
                 ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?;
             ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
@@ -313,9 +313,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
             argvs.push(arg_place.to_ref(&ecx));
         }
         // Make an array with all these pointers, in the Miri memory.
-        let argvs_layout = ecx.layout_of(
-            Ty::new_array(tcx,Ty::new_imm_ptr(tcx,tcx.types.u8), u64::try_from(argvs.len()).unwrap()),
-        )?;
+        let argvs_layout = ecx.layout_of(Ty::new_array(
+            tcx,
+            Ty::new_imm_ptr(tcx, tcx.types.u8),
+            u64::try_from(argvs.len()).unwrap(),
+        ))?;
         let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
         for (idx, arg) in argvs.into_iter().enumerate() {
             let place = ecx.mplace_field(&argvs_place, idx)?;
@@ -333,7 +335,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
             ecx.machine.argc = Some(*argc_place);
 
             let argv_place = ecx.allocate(
-                ecx.layout_of(Ty::new_imm_ptr(tcx,tcx.types.unit))?,
+                ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?,
                 MiriMemoryKind::Machine.into(),
             )?;
             ecx.write_immediate(argv, &argv_place.into())?;
@@ -345,7 +347,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
             // Construct a command string with all the arguments.
             let cmd_utf16: Vec<u16> = args_to_utf16_command_string(config.args.iter());
 
-            let cmd_type = Ty::new_array(tcx,tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
+            let cmd_type =
+                Ty::new_array(tcx, tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
             let cmd_place =
                 ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?;
             ecx.machine.cmd_line = Some(*cmd_place);
@@ -366,7 +369,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
 
     match entry_type {
         EntryFnType::Main { .. } => {
-            let start_id = tcx.lang_items().start_fn().unwrap();
+            let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| {
+                tcx.sess.fatal(
+                    "could not find start function. Make sure the entry point is marked with `#[start]`."
+                );
+            });
             let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
             let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
             let start_instance = ty::Instance::resolve(
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index e79bb47c78b..7e92dc7a0c7 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -9,6 +9,7 @@
 #![feature(local_key_cell_methods)]
 #![feature(round_ties_even)]
 #![feature(os_str_bytes)]
+#![feature(lint_reasons)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 5fcf3905199..ac2bad22119 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -313,10 +313,12 @@ pub struct PrimitiveLayouts<'tcx> {
 impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
     fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> {
         let tcx = layout_cx.tcx;
-        let mut_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
-        let const_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
+        let mut_raw_ptr =
+            Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
+        let const_raw_ptr =
+            Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
         Ok(Self {
-            unit: layout_cx.layout_of(Ty::new_unit(tcx,))?,
+            unit: layout_cx.layout_of(Ty::new_unit(tcx))?,
             i8: layout_cx.layout_of(tcx.types.i8)?,
             i16: layout_cx.layout_of(tcx.types.i16)?,
             i32: layout_cx.layout_of(tcx.types.i32)?,
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index eaa66f1f874..adf9a35d5c3 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let len: u64 = ptrs.len().try_into().unwrap();
 
         let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
-        let array_layout = this.layout_of(Ty::new_array(tcx.tcx,ptr_ty, len)).unwrap();
+        let array_layout = this.layout_of(Ty::new_array(tcx.tcx, ptr_ty, len)).unwrap();
 
         match flags {
             // storage for pointers is allocated by miri
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index 3d4967f1f83..1dcb877a83f 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -5,8 +5,8 @@ use std::mem;
 
 use rustc_const_eval::interpret::Pointer;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::Ty;
 use rustc_target::abi::Size;
 
 use crate::helpers::target_os_is_unix;
@@ -449,9 +449,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         vars.push(Pointer::null());
         // Make an array with all these pointers inside Miri.
         let tcx = this.tcx;
-        let vars_layout = this.layout_of(
-            Ty::new_array(tcx.tcx,this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()),
-        )?;
+        let vars_layout = this.layout_of(Ty::new_array(
+            tcx.tcx,
+            this.machine.layouts.mut_raw_ptr.ty,
+            u64::try_from(vars.len()).unwrap(),
+        ))?;
         let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
         for (idx, var) in vars.into_iter().enumerate() {
             let place = this.mplace_field(&vars_place, idx)?;
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index f4e91c30d9f..6915c396d61 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -763,6 +763,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let ptr_dest = this.read_pointer(ptr_dest)?;
                 let ptr_src = this.read_pointer(ptr_src)?;
                 let n = this.read_target_usize(n)?;
+
+                // C requires that this must always be a valid pointer, even if `n` is zero, so we better check that.
+                // (This is more than Rust requires, so `mem_copy` is not sufficient.)
+                this.ptr_get_alloc_id(ptr_dest)?;
+                this.ptr_get_alloc_id(ptr_src)?;
+
                 this.mem_copy(
                     ptr_src,
                     Align::ONE,
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index 1995db715e8..94f8cfbfb1c 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -483,7 +483,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 // `index` is an array, not a SIMD type
                 let ty::Array(_, index_len) = index.layout.ty.kind() else {
-                    span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty)
+                    span_bug!(
+                        this.cur_span(),
+                        "simd_shuffle index argument has non-array type {}",
+                        index.layout.ty
+                    )
                 };
                 let index_len = index_len.eval_target_usize(*this.tcx, this.param_env());
 
@@ -622,9 +626,7 @@ fn fmax_op<'tcx>(
     right: &ImmTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, Scalar<Provenance>> {
     assert_eq!(left.layout.ty, right.layout.ty);
-    let ty::Float(float_ty) = left.layout.ty.kind() else {
-        bug!("fmax operand is not a float")
-    };
+    let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmax operand is not a float") };
     let left = left.to_scalar();
     let right = right.to_scalar();
     Ok(match float_ty {
@@ -638,9 +640,7 @@ fn fmin_op<'tcx>(
     right: &ImmTy<'tcx, Provenance>,
 ) -> InterpResult<'tcx, Scalar<Provenance>> {
     assert_eq!(left.layout.ty, right.layout.ty);
-    let ty::Float(float_ty) = left.layout.ty.kind() else {
-        bug!("fmin operand is not a float")
-    };
+    let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmin operand is not a float") };
     let left = left.to_scalar();
     let right = right.to_scalar();
     Ok(match float_ty {
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index 4cdd54fa21b..f08f0aad5e7 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -7,8 +7,8 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt};
 #[cfg(windows)]
 use std::os::windows::ffi::{OsStrExt, OsStringExt};
 
-use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::Ty;
 
 use crate::*;
 
@@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator.
         let this = self.eval_context_mut();
 
-        let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u8, size);
+        let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u8, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
         let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
         assert!(written);
@@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator.
         let this = self.eval_context_mut();
 
-        let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u16, size);
+        let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
         let (written, _) =
             self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap();
diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs
index dc395d39ce1..87e887000c5 100644
--- a/src/tools/miri/src/shims/unix/linux/fd.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd.rs
@@ -181,6 +181,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     /// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics.
     ///
     /// <https://linux.die.net/man/2/eventfd>
+    #[expect(clippy::needless_if)]
     fn eventfd(
         &mut self,
         val: &OpTy<'tcx, Provenance>,
diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs
index 73671e716ef..59143550253 100644
--- a/src/tools/miri/tests/compiletest.rs
+++ b/src/tools/miri/tests/compiletest.rs
@@ -145,7 +145,8 @@ fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> R
         // The files we're actually interested in (all `.rs` files).
         |path| {
             path.extension().is_some_and(|ext| ext == "rs")
-                && (filters.is_empty() || filters.iter().any(|f| path.starts_with(f)))
+                && (filters.is_empty()
+                    || filters.iter().any(|f| path.display().to_string().contains(f)))
         },
         // This could be used to overwrite the `Config` on a per-test basis.
         |_, _| None,
@@ -274,13 +275,13 @@ fn main() -> Result<()> {
 fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> {
     let path = args.next().expect("./miri run-dep must be followed by a file name");
     let mut config = test_config(&target, "", Mode::Yolo, /* with dependencies */ true);
-    config.program.args.remove(0); // remove the `--error-format=json` argument
-    config.program.args.push("--color".into());
-    config.program.args.push("always".into());
-    let mut cmd = ui_test::test_command(config, Path::new(&path))?;
-    // Separate the arguments to the `cargo miri` invocation from
-    // the arguments to the interpreted prog
-    cmd.arg("--");
+    config.program.args.clear(); // We want to give the user full control over flags
+    config.build_dependencies_and_link_them()?;
+
+    let mut cmd = config.program.build(&config.out_dir);
+
+    cmd.arg(path);
+
     cmd.args(args);
     if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) }
 }
diff --git a/src/tools/miri/tests/fail/shims/memchr_null.rs b/src/tools/miri/tests/fail/shims/memchr_null.rs
new file mode 100644
index 00000000000..6bc7af7e6bf
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memchr_null.rs
@@ -0,0 +1,10 @@
+//@ignore-target-windows: No libc on Windows
+
+use std::ptr;
+
+// null is explicitly called out as UB in the C docs.
+fn main() {
+    unsafe {
+        libc::memchr(ptr::null(), 0, 0); //~ERROR: dangling
+    }
+}
diff --git a/src/tools/miri/tests/fail/shims/memchr_null.stderr b/src/tools/miri/tests/fail/shims/memchr_null.stderr
new file mode 100644
index 00000000000..d48606f34ad
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memchr_null.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
+  --> $DIR/memchr_null.rs:LL:CC
+   |
+LL |         libc::memchr(ptr::null(), 0, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/memchr_null.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/shims/memcmp_null.rs b/src/tools/miri/tests/fail/shims/memcmp_null.rs
new file mode 100644
index 00000000000..a4e0034c40b
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memcmp_null.rs
@@ -0,0 +1,10 @@
+//@ignore-target-windows: No libc on Windows
+
+use std::ptr;
+
+// null is explicitly called out as UB in the C docs.
+fn main() {
+    unsafe {
+        libc::memcmp(ptr::null(), ptr::null(), 0); //~ERROR: dangling
+    }
+}
diff --git a/src/tools/miri/tests/fail/shims/memcmp_null.stderr b/src/tools/miri/tests/fail/shims/memcmp_null.stderr
new file mode 100644
index 00000000000..7a09c779894
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memcmp_null.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
+  --> $DIR/memcmp_null.rs:LL:CC
+   |
+LL |         libc::memcmp(ptr::null(), ptr::null(), 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/memcmp_null.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/shims/memcpy_zero.rs b/src/tools/miri/tests/fail/shims/memcpy_zero.rs
new file mode 100644
index 00000000000..5283fea4cb9
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memcpy_zero.rs
@@ -0,0 +1,12 @@
+//@ignore-target-windows: No libc on Windows
+//@compile-flags: -Zmiri-permissive-provenance
+// C's memcpy is 0 bytes is UB for some pointers that are allowed in Rust's `copy_nonoverlapping`.
+
+fn main() {
+    let from = 42 as *const u8;
+    let to = 23 as *mut u8;
+    unsafe {
+        to.copy_from(from, 0); // this is fine
+        libc::memcpy(to.cast(), from.cast(), 0); //~ERROR: dangling
+    }
+}
diff --git a/src/tools/miri/tests/fail/shims/memcpy_zero.stderr b/src/tools/miri/tests/fail/shims/memcpy_zero.stderr
new file mode 100644
index 00000000000..7c1c3fe20c4
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memcpy_zero.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance)
+  --> $DIR/memcpy_zero.rs:LL:CC
+   |
+LL |         libc::memcpy(to.cast(), from.cast(), 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance)
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/memcpy_zero.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/shims/memrchr_null.rs b/src/tools/miri/tests/fail/shims/memrchr_null.rs
new file mode 100644
index 00000000000..b6707d558d8
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memrchr_null.rs
@@ -0,0 +1,11 @@
+//@ignore-target-windows: No libc on Windows
+//@ignore-target-apple: No `memrchr` on some apple targets
+
+use std::ptr;
+
+// null is explicitly called out as UB in the C docs.
+fn main() {
+    unsafe {
+        libc::memrchr(ptr::null(), 0, 0); //~ERROR: dangling
+    }
+}
diff --git a/src/tools/miri/tests/fail/shims/memrchr_null.stderr b/src/tools/miri/tests/fail/shims/memrchr_null.stderr
new file mode 100644
index 00000000000..b5b7630e7fd
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/memrchr_null.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
+  --> $DIR/memrchr_null.rs:LL:CC
+   |
+LL |         libc::memrchr(ptr::null(), 0, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/memrchr_null.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs
index 048f7d1c351..4ab2bcb7f22 100644
--- a/src/tools/miri/tests/pass/vec.rs
+++ b/src/tools/miri/tests/pass/vec.rs
@@ -100,7 +100,7 @@ fn vec_push_ptr_stable() {
     v.push(0);
     let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
     v.push(1);
-    let _val = *v0;
+    *v0 = *v0;
 }
 
 fn vec_extend_ptr_stable() {
@@ -109,23 +109,23 @@ fn vec_extend_ptr_stable() {
     let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
     // `slice::Iter` (with `T: Copy`) specialization
     v.extend(&[1]);
-    let _val = *v0;
+    *v0 = *v0;
     // `vec::IntoIter` specialization
     v.extend(vec![2]);
-    let _val = *v0;
+    *v0 = *v0;
     // `TrustedLen` specialization
     v.extend(std::iter::once(3));
-    let _val = *v0;
+    *v0 = *v0;
     // base case
     v.extend(std::iter::once(3).filter(|_| true));
-    let _val = *v0;
+    *v0 = *v0;
 }
 
 fn vec_truncate_ptr_stable() {
     let mut v = vec![0; 10];
     let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
     v.truncate(5);
-    let _val = *v0;
+    *v0 = *v0;
 }
 
 fn push_str_ptr_stable() {