about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/.github/workflows/ci.yml72
-rw-r--r--src/tools/miri/README.md2
-rw-r--r--src/tools/miri/bench-cargo-miri/mse/src/main.rs2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs111
-rw-r--r--src/tools/miri/src/bin/miri.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs15
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs2
-rw-r--r--src/tools/miri/src/helpers.rs2
-rw-r--r--src/tools/miri/src/machine.rs5
-rw-r--r--src/tools/miri/src/shims/time.rs33
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs433
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs17
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs5
-rw-r--r--src/tools/miri/src/shims/windows/fs.rs19
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs9
-rw-r--r--src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs9
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs6
-rw-r--r--src/tools/miri/tests/fail/no_main.stderr2
-rw-r--r--src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs2
-rw-r--r--src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr4
-rw-r--r--src/tools/miri/tests/pass-dep/shims/windows-fs.rs25
-rw-r--r--src/tools/miri/tests/pass/async-drop.rs10
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs2
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs178
47 files changed, 799 insertions, 304 deletions
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 59bae513a58..9dbf51e9796 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -89,41 +89,16 @@ jobs:
             # Check if all jobs that we depend on (in the needs array) were successful.
             jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
 
-  cron-fail-notify:
-    name: cronjob failure notification
+  cron-rustc-pull:
+    name: automatic pull from rustc
     runs-on: ubuntu-latest
     permissions:
         # The cronjob needs to be able to push to the repo...
         contents: write
         # ... and create a PR.
         pull-requests: write
-    needs: [build, style, coverage]
-    if: ${{ github.event_name == 'schedule' && failure() }}
+    if: ${{ github.event_name == 'schedule' }}
     steps:
-      # Send a Zulip notification
-      - name: Install zulip-send
-        run: pip3 install zulip
-      - name: Send Zulip notification
-        env:
-          ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
-          ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
-        run: |
-          ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
-            --stream miri --subject "Miri Build Failure ($(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.
-
-          This likely means that rustc changed the miri directory and
-          we now need to do a [`./miri rustc-pull`](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#importing-changes-from-the-rustc-repo).
-
-          Would you mind investigating this issue?
-
-          Thanks in advance!
-          Sincerely,
-          The Miri Cronjobs Bot'
-
-      # Attempt to auto-sync with rustc
       - uses: actions/checkout@v4
         with:
           fetch-depth: 256 # get a bit more of the history
@@ -143,18 +118,45 @@ jobs:
         run: |
           ./miri toolchain
           ./miri fmt --check || (./miri fmt && git commit -am "fmt")
-      - name: Push changes to a branch
+      - name: Push changes to a branch and create PR
         run: |
+          # `git diff --exit-code` "succeeds" if the diff is empty.
+          if git diff --exit-code HEAD^; then echo "Nothing changed in rustc, skipping PR"; exit 0; fi
+          # The diff is non-empty, create a PR.
           BRANCH="rustup-$(date -u +%Y-%m-%d)"
           git switch -c $BRANCH
           git push -u origin $BRANCH
-      - name: Create Pull Request
-        run: |
-          PR=$(gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.')
-          ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
-            --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \
-            --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
+          gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.'
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
           ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
+
+  cron-fail-notify:
+    name: cronjob failure notification
+    runs-on: ubuntu-latest
+    needs: [build, style, coverage]
+    if: ${{ github.event_name == 'schedule' && failure() }}
+    steps:
+      # Send a Zulip notification
+      - name: Install zulip-send
+        run: pip3 install zulip
+      - name: Send Zulip notification
+        env:
+          ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
+          ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
+        run: |
+          ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
+            --stream miri --subject "Miri Build Failure ($(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.
+
+          This likely means that rustc changed the miri directory and
+          we now need to do a [`./miri rustc-pull`](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#importing-changes-from-the-rustc-repo).
+
+          Would you mind investigating this issue?
+
+          Thanks in advance!
+          Sincerely,
+          The Miri Cronjobs Bot'
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index e8ea988558c..95e1770aa7b 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -489,7 +489,7 @@ Miri knows where it is supposed to start execution:
 
 ```rust
 #[cfg(miri)]
-#[no_mangle]
+#[unsafe(no_mangle)]
 fn miri_start(argc: isize, argv: *const *const u8) -> isize {
     // Call the actual start function that your project implements, based on your target's conventions.
 }
diff --git a/src/tools/miri/bench-cargo-miri/mse/src/main.rs b/src/tools/miri/bench-cargo-miri/mse/src/main.rs
index 06d5487d1d4..69c7c39cdd7 100644
--- a/src/tools/miri/bench-cargo-miri/mse/src/main.rs
+++ b/src/tools/miri/bench-cargo-miri/mse/src/main.rs
@@ -13,7 +13,7 @@ fn read_i16(buffer: &[u8], index: usize) -> i16 {
     const SIZE: usize = size_of::<i16>();
     let mut bytes: [u8; SIZE] = [0u8; SIZE];
     bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]);
-    unsafe { std::mem::transmute(bytes) }
+    i16::from_ne_bytes(bytes)
 }
 
 fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 {
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index d1107e51509..59d53891217 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-1bc56185ee257ed829a0aea7abdc3b03c5fed887
+1b8ab72680f36e783af84c1a3c4f8508572bd9f9
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index c263e86c082..335e8d76999 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -107,47 +107,6 @@ fn align_addr(addr: u64, align: u64) -> u64 {
 
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    // Returns the exposed `AllocId` that corresponds to the specified addr,
-    // or `None` if the addr is out of bounds
-    fn alloc_id_from_addr(&self, addr: u64, size: i64) -> Option<AllocId> {
-        let this = self.eval_context_ref();
-        let global_state = this.machine.alloc_addresses.borrow();
-        assert!(global_state.provenance_mode != ProvenanceMode::Strict);
-
-        // We always search the allocation to the right of this address. So if the size is structly
-        // negative, we have to search for `addr-1` instead.
-        let addr = if size >= 0 { addr } else { addr.saturating_sub(1) };
-        let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr);
-
-        // Determine the in-bounds provenance for this pointer.
-        let alloc_id = match pos {
-            Ok(pos) => Some(global_state.int_to_ptr_map[pos].1),
-            Err(0) => None,
-            Err(pos) => {
-                // This is the largest of the addresses smaller than `int`,
-                // i.e. the greatest lower bound (glb)
-                let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
-                // This never overflows because `addr >= glb`
-                let offset = addr - glb;
-                // We require this to be strict in-bounds of the allocation. This arm is only
-                // entered for addresses that are not the base address, so even zero-sized
-                // allocations will get recognized at their base address -- but all other
-                // allocations will *not* be recognized at their "end" address.
-                let size = this.get_alloc_info(alloc_id).size;
-                if offset < size.bytes() { Some(alloc_id) } else { None }
-            }
-        }?;
-
-        // We only use this provenance if it has been exposed.
-        if global_state.exposed.contains(&alloc_id) {
-            // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed.
-            debug_assert!(this.is_alloc_live(alloc_id));
-            Some(alloc_id)
-        } else {
-            None
-        }
-    }
-
     fn addr_from_alloc_id_uncached(
         &self,
         global_state: &mut GlobalStateInner,
@@ -242,11 +201,65 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             interp_ok(base_addr)
         }
     }
+}
 
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    // Returns the `AllocId` that corresponds to the specified addr,
+    // or `None` if the addr is out of bounds.
+    // Setting `only_exposed_allocations` selects whether only exposed allocations are considered.
+    fn alloc_id_from_addr(
+        &self,
+        addr: u64,
+        size: i64,
+        only_exposed_allocations: bool,
+    ) -> Option<AllocId> {
+        let this = self.eval_context_ref();
+        let global_state = this.machine.alloc_addresses.borrow();
+        assert!(global_state.provenance_mode != ProvenanceMode::Strict);
+
+        // We always search the allocation to the right of this address. So if the size is strictly
+        // negative, we have to search for `addr-1` instead.
+        let addr = if size >= 0 { addr } else { addr.saturating_sub(1) };
+        let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr);
+
+        // Determine the in-bounds provenance for this pointer.
+        let alloc_id = match pos {
+            Ok(pos) => Some(global_state.int_to_ptr_map[pos].1),
+            Err(0) => None,
+            Err(pos) => {
+                // This is the largest of the addresses smaller than `int`,
+                // i.e. the greatest lower bound (glb)
+                let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
+                // This never overflows because `addr >= glb`
+                let offset = addr - glb;
+                // We require this to be strict in-bounds of the allocation. This arm is only
+                // entered for addresses that are not the base address, so even zero-sized
+                // allocations will get recognized at their base address -- but all other
+                // allocations will *not* be recognized at their "end" address.
+                let size = this.get_alloc_info(alloc_id).size;
+                if offset < size.bytes() { Some(alloc_id) } else { None }
+            }
+        }?;
+
+        // We only use this provenance if it has been exposed, or if the caller requested also non-exposed allocations
+        if !only_exposed_allocations || global_state.exposed.contains(&alloc_id) {
+            // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed.
+            debug_assert!(this.is_alloc_live(alloc_id));
+            Some(alloc_id)
+        } else {
+            None
+        }
+    }
+
+    /// Returns the base address of an allocation, or an error if no base address could be found
+    ///
+    /// # Panics
+    /// If `memory_kind = None` and the `alloc_id` is not cached, meaning that the first call to this function per `alloc_id` must get the `memory_kind`.
     fn addr_from_alloc_id(
         &self,
         alloc_id: AllocId,
-        memory_kind: MemoryKind,
+        memory_kind: Option<MemoryKind>,
     ) -> InterpResult<'tcx, u64> {
         let this = self.eval_context_ref();
         let mut global_state = this.machine.alloc_addresses.borrow_mut();
@@ -256,8 +269,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some(&addr) => interp_ok(addr),
             None => {
                 // First time we're looking for the absolute address of this allocation.
+                let memory_kind =
+                    memory_kind.expect("memory_kind is required since alloc_id is not cached");
                 let base_addr =
-                    self.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?;
+                    this.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?;
                 trace!("Assigning base address {:#x} to allocation {:?}", base_addr, alloc_id);
 
                 // Store address in cache.
@@ -283,10 +298,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
     }
-}
 
-impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
-pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn expose_provenance(&self, provenance: Provenance) -> InterpResult<'tcx> {
         let this = self.eval_context_ref();
         let mut global_state = this.machine.alloc_addresses.borrow_mut();
@@ -365,7 +377,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let alloc_id = prov.alloc_id();
 
         // Get a pointer to the beginning of this allocation.
-        let base_addr = this.addr_from_alloc_id(alloc_id, kind)?;
+        let base_addr = this.addr_from_alloc_id(alloc_id, Some(kind))?;
         let base_ptr = interpret::Pointer::new(
             Provenance::Concrete { alloc_id, tag },
             Size::from_bytes(base_addr),
@@ -388,7 +400,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`.
             // This additional call ensures that some `MiriAllocBytes` are always prepared, just in case
             // this function gets called before the first time `addr_from_alloc_id` gets called.
-            this.addr_from_alloc_id(id, MiriMemoryKind::Global.into())?;
+            this.addr_from_alloc_id(id, Some(MiriMemoryKind::Global.into()))?;
             // The memory we need here will have already been allocated during an earlier call to
             // `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead
             // fetch the previously prepared bytes from `prepared_alloc_bytes`.
@@ -423,7 +435,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             alloc_id
         } else {
             // A wildcard pointer.
-            this.alloc_id_from_addr(addr.bytes(), size)?
+            let only_exposed_allocations = true;
+            this.alloc_id_from_addr(addr.bytes(), size, only_exposed_allocations)?
         };
 
         // This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 4e8fe0ca8ad..8ff1c9d6ff0 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -106,7 +106,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
         } else {
             tcx.dcx().fatal(
                 "`miri_start` must have the following signature:\n\
-                        fn miri_start(argc: isize, argv: *const *const u8) -> isize",
+                fn miri_start(argc: isize, argv: *const *const u8) -> isize",
             );
         }
     } else {
@@ -115,7 +115,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
             Alternatively, you can export a `miri_start` function:\n\
             \n\
             #[cfg(miri)]\n\
-            #[no_mangle]\n\
+            #[unsafe(no_mangle)]\n\
             fn miri_start(argc: isize, argv: *const *const u8) -> isize {\
             \n    // Call the actual start function that your project implements, based on your target's conventions.\n\
             }"
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index a429940748c..dbfa9807e3b 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -61,8 +61,7 @@ fn all_read_accesses_commute() {
                 // ... and produce the same final result.
                 assert_eq!(
                     loc12, loc21,
-                    "Read accesses {:?} followed by {:?} do not commute !",
-                    rel1, rel2
+                    "Read accesses {rel1:?} followed by {rel2:?} do not commute !"
                 );
             }
         }
@@ -674,8 +673,8 @@ mod spurious_read {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             let (x, y) = self.retag_permissions();
             write!(f, "{}; ", self.xy_rel)?;
-            write!(f, "y: ({}); ", y,)?;
-            write!(f, "retag x ({}); ", x)?;
+            write!(f, "y: ({y}); ")?;
+            write!(f, "retag x ({x}); ")?;
 
             write!(f, "<arbitrary code>; <spurious read x>;")?;
             Ok(())
@@ -730,17 +729,17 @@ mod spurious_read {
                         // protector.
                         final_source
                             .distinguishable::</*X*/ AllowRet, /*Y*/ AllowRet>(&final_target)
-                            .then_some(format!("{}", final_target))
+                            .then_some(format!("{final_target}"))
                     } else {
                         Some(format!("UB"))
                     }
                 };
                 if let Some(final_target) = distinguishable {
                     eprintln!(
-                        "For pattern '{}', inserting a spurious read through x makes the final state '{}' instead of '{}' which is observable",
-                        pat, final_target, final_source
+                        "For pattern '{pat}', inserting a spurious read through x makes the final state '{final_target}' \
+                        instead of '{final_source}' which is observable"
                     );
-                    eprintln!("  (arbitrary code instanciated with '{}')", opaque);
+                    eprintln!("  (arbitrary code instanciated with '{opaque}')");
                     err += 1;
                     // We found an instanciation of the opaque code that makes this Pattern
                     // fail, we don't really need to check the rest.
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 923031dbbd1..847c6823475 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -381,7 +381,7 @@ impl AccessType {
         });
 
         if let Some(ty) = ty {
-            msg.push_str(&format!(" of type `{}`", ty));
+            msg.push_str(&format!(" of type `{ty}`"));
         }
 
         msg
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 1af3d1abc64..a3aa8bbbfb3 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     /// Check that the given `caller_fn_abi` matches the expected ABI described by
-    /// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and the return the list of
+    /// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and then returns the list of
     /// arguments.
     fn check_shim_abi<'a, const N: usize>(
         &mut self,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index ea59d327be8..c3d841353a8 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -721,9 +721,8 @@ impl<'tcx> MiriMachine<'tcx> {
                 // Check if host target == the session target.
                 if host_triple != target_triple {
                     panic!(
-                        "calling external C functions in linked .so file requires host and target to be the same: host={}, target={}",
-                        host_triple,
-                        target_triple,
+                        "calling native C functions in linked .so file requires host and target to be the same: \
+                        host={host_triple}, target={target_triple}",
                     );
                 }
                 // Note: it is the user's responsibility to provide a correct SO file.
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index fb80a36af9f..28f4ca5bb1b 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -21,7 +21,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         clk_id_op: &OpTy<'tcx>,
         tp_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, Scalar> {
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
         // This clock support is deliberately minimal because a lot of clock types have fiddly
         // properties (is it possible for Miri to be suspended independently of the host?). If you
         // have a use for another clock type, please open an issue.
@@ -29,8 +30,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         this.assert_target_os_is_unix("clock_gettime");
+        let clockid_t_size = this.libc_ty_layout("clockid_t").size;
 
-        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
+        let clk_id = this.read_scalar(clk_id_op)?.to_int(clockid_t_size)?;
         let tp = this.deref_pointer_as(tp_op, this.libc_ty_layout("timespec"))?;
 
         let absolute_clocks;
@@ -43,34 +45,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
                 // is just specified to be "faster and less precise", so we implement both the same way.
                 absolute_clocks = vec![
-                    this.eval_libc_i32("CLOCK_REALTIME"),
-                    this.eval_libc_i32("CLOCK_REALTIME_COARSE"),
+                    this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?,
+                    this.eval_libc("CLOCK_REALTIME_COARSE").to_int(clockid_t_size)?,
                 ];
                 // The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are
                 // never allowed to go backwards. We don't need to do any additional monotonicity
                 // enforcement because std::time::Instant already guarantees that it is monotonic.
                 relative_clocks = vec![
-                    this.eval_libc_i32("CLOCK_MONOTONIC"),
-                    this.eval_libc_i32("CLOCK_MONOTONIC_COARSE"),
+                    this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?,
+                    this.eval_libc("CLOCK_MONOTONIC_COARSE").to_int(clockid_t_size)?,
                 ];
             }
             "macos" => {
-                absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")];
-                relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")];
+                absolute_clocks = vec![this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?];
+                relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?];
                 // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
                 // that's not really something a program running inside Miri can tell, anyway.
                 // We need to support it because std uses it.
-                relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW"));
+                relative_clocks.push(this.eval_libc("CLOCK_UPTIME_RAW").to_int(clockid_t_size)?);
             }
             "solaris" | "illumos" => {
                 // The REALTIME clock returns the actual time since the Unix epoch.
-                absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")];
+                absolute_clocks = vec![this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?];
                 // MONOTONIC, in the other hand, is the high resolution, non-adjustable
                 // clock from an arbitrary time in the past.
                 // Note that the man page mentions HIGHRES but it is just
                 // an alias of MONOTONIC and the libc crate does not expose it anyway.
                 // https://docs.oracle.com/cd/E23824_01/html/821-1465/clock-gettime-3c.html
-                relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")];
+                relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?];
             }
             target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"),
         }
@@ -81,15 +83,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else if relative_clocks.contains(&clk_id) {
             this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch())
         } else {
-            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
+            return this.set_last_error_and_return(LibcError("EINVAL"), dest);
         };
 
         let tv_sec = duration.as_secs();
         let tv_nsec = duration.subsec_nanos();
 
         this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &tp)?;
+        this.write_int(0, dest)?;
 
-        interp_ok(Scalar::from_i32(0))
+        interp_ok(())
     }
 
     fn gettimeofday(
@@ -188,10 +191,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 tm_zone.push('+');
             }
             let offset_hour = offset_in_seconds.abs() / 3600;
-            write!(tm_zone, "{:02}", offset_hour).unwrap();
+            write!(tm_zone, "{offset_hour:02}").unwrap();
             let offset_min = (offset_in_seconds.abs() % 3600) / 60;
             if offset_min != 0 {
-                write!(tm_zone, "{:02}", offset_min).unwrap();
+                write!(tm_zone, "{offset_min:02}").unwrap();
             }
 
             // Add null terminator for C string compatibility.
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 5e6259c3574..026aa1f9503 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -112,51 +112,122 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // Environment related shims
             "getenv" => {
-                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty],
+                    this.machine.layouts.mut_raw_ptr.ty,
+                    args,
+                )?;
                 let result = this.getenv(name)?;
                 this.write_pointer(result, dest)?;
             }
             "unsetenv" => {
-                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.unsetenv(name)?;
                 this.write_scalar(result, dest)?;
             }
             "setenv" => {
-                let [name, value, overwrite] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name, value, overwrite] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.machine.layouts.const_raw_ptr.ty,
+                        this.machine.layouts.const_raw_ptr.ty,
+                        this.tcx.types.i32,
+                    ],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 this.read_scalar(overwrite)?.to_i32()?;
                 let result = this.setenv(name, value)?;
                 this.write_scalar(result, dest)?;
             }
             "getcwd" => {
-                let [buf, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [buf, size] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
+                    this.machine.layouts.mut_raw_ptr.ty,
+                    args,
+                )?;
                 let result = this.getcwd(buf, size)?;
                 this.write_pointer(result, dest)?;
             }
             "chdir" => {
-                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.chdir(path)?;
                 this.write_scalar(result, dest)?;
             }
             "getpid" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [],
+                    this.libc_ty_layout("pid_t").ty,
+                    args,
+                )?;
                 let result = this.getpid()?;
                 this.write_scalar(result, dest)?;
             }
             "sysconf" => {
-                let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let result = this.sysconf(val)?;
                 this.write_scalar(result, dest)?;
             }
             // File descriptors
             "read" => {
-                let [fd, buf, count] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf, count] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
                 this.read(fd, buf, count, None, dest)?;
             }
             "write" => {
-                let [fd, buf, n] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf, n] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.tcx.types.i32,
+                        this.machine.layouts.const_raw_ptr.ty,
+                        this.tcx.types.usize,
+                    ],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
@@ -164,38 +235,88 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write(fd, buf, count, None, dest)?;
             }
             "pread" => {
-                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off_t = this.libc_ty_layout("off_t");
+                let [fd, buf, count, offset] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.tcx.types.i32,
+                        this.machine.layouts.mut_raw_ptr.ty,
+                        this.tcx.types.usize,
+                        off_t.ty,
+                    ],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
-                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
+                let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
                 this.read(fd, buf, count, Some(offset), dest)?;
             }
             "pwrite" => {
-                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off_t = this.libc_ty_layout("off_t");
+                let [fd, buf, n, offset] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.tcx.types.i32,
+                        this.machine.layouts.const_raw_ptr.ty,
+                        this.tcx.types.usize,
+                        off_t.ty,
+                    ],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
-                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
+                let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
                 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
                 this.write(fd, buf, count, Some(offset), dest)?;
             }
             "pread64" => {
-                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off64_t = this.libc_ty_layout("off64_t");
+                let [fd, buf, count, offset] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.tcx.types.i32,
+                        this.machine.layouts.mut_raw_ptr.ty,
+                        this.tcx.types.usize,
+                        off64_t.ty,
+                    ],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
-                let offset =
-                    this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
                 this.read(fd, buf, count, Some(offset), dest)?;
             }
             "pwrite64" => {
-                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off64_t = this.libc_ty_layout("off64_t");
+                let [fd, buf, n, offset] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.tcx.types.i32,
+                        this.machine.layouts.const_raw_ptr.ty,
+                        this.tcx.types.usize,
+                        off64_t.ty,
+                    ],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
-                let offset =
-                    this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
                 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
                 this.write(fd, buf, count, Some(offset), dest)?;
             }
@@ -218,13 +339,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "dup" => {
-                let [old_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [old_fd] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.dup(old_fd)?;
                 this.write_scalar(new_fd, dest)?;
             }
             "dup2" => {
-                let [old_fd, new_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [old_fd, new_fd] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, this.tcx.types.i32],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
                 let result = this.dup2(old_fd, new_fd)?;
@@ -233,7 +368,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "flock" => {
                 // Currently this function does not exist on all Unixes, e.g. on Solaris.
                 this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?;
-                let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, op] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, this.tcx.types.i32],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let op = this.read_scalar(op)?.to_i32()?;
                 let result = this.flock(fd, op)?;
@@ -250,140 +392,311 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "unlink" => {
-                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.unlink(path)?;
                 this.write_scalar(result, dest)?;
             }
             "symlink" => {
-                let [target, linkpath] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [target, linkpath] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.symlink(target, linkpath)?;
                 this.write_scalar(result, dest)?;
             }
             "rename" => {
-                let [oldpath, newpath] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [oldpath, newpath] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.rename(oldpath, newpath)?;
                 this.write_scalar(result, dest)?;
             }
             "mkdir" => {
-                let [path, mode] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, mode] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty, this.libc_ty_layout("mode_t").ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.mkdir(path, mode)?;
                 this.write_scalar(result, dest)?;
             }
             "rmdir" => {
-                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.rmdir(path)?;
                 this.write_scalar(result, dest)?;
             }
             "opendir" => {
-                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty],
+                    this.machine.layouts.mut_raw_ptr.ty,
+                    args,
+                )?;
                 let result = this.opendir(name)?;
                 this.write_scalar(result, dest)?;
             }
             "closedir" => {
-                let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.mut_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.closedir(dirp)?;
                 this.write_scalar(result, dest)?;
             }
             "lseek64" => {
-                let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off64_t = this.libc_ty_layout("off64_t");
+                let [fd, offset, whence] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, off64_t.ty, this.tcx.types.i32],
+                    off64_t.ty,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
-                let offset = this.read_scalar(offset)?.to_i64()?;
+                let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
                 let whence = this.read_scalar(whence)?.to_i32()?;
-                let result = this.lseek64(fd, offset.into(), whence)?;
-                this.write_scalar(result, dest)?;
+                this.lseek64(fd, offset, whence, dest)?;
             }
             "lseek" => {
-                let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off_t = this.libc_ty_layout("off_t");
+                let [fd, offset, whence] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, off_t.ty, this.tcx.types.i32],
+                    off_t.ty,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
-                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
+                let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
                 let whence = this.read_scalar(whence)?.to_i32()?;
-                let result = this.lseek64(fd, offset, whence)?;
-                this.write_scalar(result, dest)?;
+                this.lseek64(fd, offset, whence, dest)?;
             }
             "ftruncate64" => {
-                let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off64_t = this.libc_ty_layout("off64_t");
+                let [fd, length] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, off64_t.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
-                let length = this.read_scalar(length)?.to_i64()?;
-                let result = this.ftruncate64(fd, length.into())?;
+                let length = this.read_scalar(length)?.to_int(off64_t.size)?;
+                let result = this.ftruncate64(fd, length)?;
                 this.write_scalar(result, dest)?;
             }
             "ftruncate" => {
-                let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off_t = this.libc_ty_layout("off_t");
+                let [fd, length] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, off_t.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
-                let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
+                let length = this.read_scalar(length)?.to_int(off_t.size)?;
                 let result = this.ftruncate64(fd, length)?;
                 this.write_scalar(result, dest)?;
             }
             "fsync" => {
-                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.fsync(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "fdatasync" => {
-                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.fdatasync(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "readlink" => {
-                let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pathname, buf, bufsize] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.machine.layouts.const_raw_ptr.ty,
+                        this.machine.layouts.mut_raw_ptr.ty,
+                        this.tcx.types.usize,
+                    ],
+                    this.tcx.types.isize,
+                    args,
+                )?;
                 let result = this.readlink(pathname, buf, bufsize)?;
                 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
             }
             "posix_fadvise" => {
-                let [fd, offset, len, advice] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let off_t = this.libc_ty_layout("off_t");
+                let [fd, offset, len, advice] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.tcx.types.i32, off_t.ty, off_t.ty, this.tcx.types.i32],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 this.read_scalar(fd)?.to_i32()?;
-                this.read_target_isize(offset)?;
-                this.read_target_isize(len)?;
+                this.read_scalar(offset)?.to_int(off_t.size)?;
+                this.read_scalar(len)?.to_int(off_t.size)?;
                 this.read_scalar(advice)?.to_i32()?;
                 // fadvise is only informational, we can ignore it.
                 this.write_null(dest)?;
             }
             "realpath" => {
-                let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, resolved_path] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
+                    this.machine.layouts.mut_raw_ptr.ty,
+                    args,
+                )?;
                 let result = this.realpath(path, resolved_path)?;
                 this.write_scalar(result, dest)?;
             }
             "mkstemp" => {
-                let [template] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [template] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.mut_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.mkstemp(template)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Unnamed sockets and pipes
             "socketpair" => {
-                let [domain, type_, protocol, sv] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let [domain, type_, protocol, sv] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [
+                        this.tcx.types.i32,
+                        this.tcx.types.i32,
+                        this.tcx.types.i32,
+                        this.machine.layouts.mut_raw_ptr.ty,
+                    ],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.socketpair(domain, type_, protocol, sv)?;
                 this.write_scalar(result, dest)?;
             }
             "pipe" => {
-                let [pipefd] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pipefd] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.mut_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.pipe2(pipefd, /*flags*/ None)?;
                 this.write_scalar(result, dest)?;
             }
             "pipe2" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
                 this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?;
-                let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pipefd, flags] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.i32],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.pipe2(pipefd, Some(flags))?;
                 this.write_scalar(result, dest)?;
             }
 
             // Time
             "gettimeofday" => {
-                let [tv, tz] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [tv, tz] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.mut_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
                 let result = this.gettimeofday(tv, tz)?;
                 this.write_scalar(result, dest)?;
             }
             "localtime_r" => {
-                let [timep, result_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [timep, result_op] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
+                    this.machine.layouts.mut_raw_ptr.ty,
+                    args,
+                )?;
                 let result = this.localtime_r(timep, result_op)?;
                 this.write_pointer(result, dest)?;
             }
             "clock_gettime" => {
-                let [clk_id, tp] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.clock_gettime(clk_id, tp)?;
-                this.write_scalar(result, dest)?;
+                let [clk_id, tp] = this.check_shim_abi(
+                    link_name,
+                    abi,
+                    ExternAbi::C { unwind: false },
+                    [this.libc_ty_layout("clockid_t").ty, this.machine.layouts.mut_raw_ptr.ty],
+                    this.tcx.types.i32,
+                    args,
+                )?;
+                this.clock_gettime(clk_id, tp, dest)?;
             }
 
             // Allocation
@@ -834,7 +1147,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // These shims are enabled only when the caller is in the standard library.
             "pthread_attr_getguardsize" if this.frame_in_std() => {
                 let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let guard_size_layout = this.libc_ty_layout("size_t");
+                let guard_size_layout = this.machine.layouts.usize;
                 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
                 this.write_scalar(
                     Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index fc0f57694a7..1f6acff0787 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -502,7 +502,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
     }
 
-    fn lseek64(&mut self, fd_num: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
+    fn lseek64(
+        &mut self,
+        fd_num: i32,
+        offset: i128,
+        whence: i32,
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
         // Isolation check is done via `FileDescription` trait.
@@ -510,7 +516,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
             if offset < 0 {
                 // Negative offsets return `EINVAL`.
-                return this.set_last_error_and_return_i64(LibcError("EINVAL"));
+                return this.set_last_error_and_return(LibcError("EINVAL"), dest);
             } else {
                 SeekFrom::Start(u64::try_from(offset).unwrap())
             }
@@ -519,19 +525,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else if whence == this.eval_libc_i32("SEEK_END") {
             SeekFrom::End(i64::try_from(offset).unwrap())
         } else {
-            return this.set_last_error_and_return_i64(LibcError("EINVAL"));
+            return this.set_last_error_and_return(LibcError("EINVAL"), dest);
         };
 
         let communicate = this.machine.communicate();
 
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return this.set_last_error_and_return_i64(LibcError("EBADF"));
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
         let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
         drop(fd);
 
         let result = this.try_unwrap_io_result(result)?;
-        interp_ok(Scalar::from_i64(result))
+        this.write_int(result, dest)?;
+        interp_ok(())
     }
 
     fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 8dcadbed130..c80858c6363 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -317,6 +317,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let res = this.GetFileInformationByHandle(handle, info)?;
                 this.write_scalar(res, dest)?;
             }
+            "DeleteFileW" => {
+                let [file_name] = this.check_shim(abi, sys_conv, link_name, args)?;
+                let res = this.DeleteFileW(file_name)?;
+                this.write_scalar(res, dest)?;
+            }
 
             // Allocation
             "HeapAlloc" => {
diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs
index 32bab548969..7561bf45219 100644
--- a/src/tools/miri/src/shims/windows/fs.rs
+++ b/src/tools/miri/src/shims/windows/fs.rs
@@ -371,6 +371,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         interp_ok(this.eval_windows("c", "TRUE"))
     }
+
+    fn DeleteFileW(
+        &mut self,
+        file_name: &OpTy<'tcx>, // LPCWSTR
+    ) -> InterpResult<'tcx, Scalar> {
+        // ^ Returns BOOL (i32 on Windows)
+        let this = self.eval_context_mut();
+        this.assert_target_os("windows", "DeleteFileW");
+        this.check_no_isolation("`DeleteFileW`")?;
+
+        let file_name = this.read_path_from_wide_str(this.read_pointer(file_name)?)?;
+        match std::fs::remove_file(file_name) {
+            Ok(_) => interp_ok(this.eval_windows("c", "TRUE")),
+            Err(e) => {
+                this.set_last_error(e)?;
+                interp_ok(this.eval_windows("c", "FALSE"))
+            }
+        }
+    }
 }
 
 /// Windows FILETIME is measured in 100-nanosecs since 1601
diff --git a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs
index f73c1b6acb7..3da54b91882 100644
--- a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs
@@ -1,13 +1,8 @@
-#![feature(intrinsics)]
-
-mod rusti {
-    #[rustc_intrinsic]
-    pub unsafe fn ctlz_nonzero<T>(x: T) -> u32;
-}
+#![feature(core_intrinsics)]
 
 pub fn main() {
     unsafe {
-        use crate::rusti::*;
+        use std::intrinsics::*;
 
         ctlz_nonzero(0u8); //~ ERROR: `ctlz_nonzero` called on 0
     }
diff --git a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs
index a41cb8b1553..2b68f6713d8 100644
--- a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs
+++ b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs
@@ -1,13 +1,8 @@
-#![feature(intrinsics)]
-
-mod rusti {
-    #[rustc_intrinsic]
-    pub unsafe fn cttz_nonzero<T>(x: T) -> u32;
-}
+#![feature(core_intrinsics)]
 
 pub fn main() {
     unsafe {
-        use crate::rusti::*;
+        use std::intrinsics::*;
 
         cttz_nonzero(0u8); //~ ERROR: `cttz_nonzero` called on 0
     }
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs
index 7ee0117ffb3..831a65966ce 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs
index 22bf881cef0..a7032e97430 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs
index 571121f4019..e8c98761956 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs
index 12600ef6125..c8b29cbcfe9 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs
index f848a137c27..0996d0244e8 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs
index 43ef4a95738..f28227134d8 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs
index 83432c2b77c..9e400b4ad40 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs
index 609443e6d4e..9aca349b918 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs
index fb3eb11c0bb..54361f6c32c 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs
index b46c4777ba7..75f52296367 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs
index 8a3b9dbdc71..20d8fa1ae80 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs
index e0c826cb046..611a0ade0a5 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs
index c7c5bf40226..8ff8c3bee00 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs
index fb3d7bda4e4..1f662e6c32a 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs
index 2cf27b33553..fad172801ea 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs
index 22dca505e64..7eb3559527a 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs
index b59c8fa8e0c..351fc6c6f1c 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs
index 4ad0cd343a4..a6f73c79710 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs
index fd47dfc03d7..b01ff3aafc0 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs
index 680ebda1c96..a573e4e852c 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs
index e4cb36c5d2e..4fb38c9bc2e 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs
index fe4bac92bd3..c4c0d3c17f0 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs
index 219efd80316..de7d2215fd6 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs
@@ -1,8 +1,6 @@
-#![feature(intrinsics)]
-
+#![feature(core_intrinsics)]
 // Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int;
+use std::intrinsics::float_to_int_unchecked;
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/no_main.stderr b/src/tools/miri/tests/fail/no_main.stderr
index e9b9e5d65b1..e7f63be794f 100644
--- a/src/tools/miri/tests/fail/no_main.stderr
+++ b/src/tools/miri/tests/fail/no_main.stderr
@@ -2,7 +2,7 @@ error: Miri can only run programs that have a main function.
        Alternatively, you can export a `miri_start` function:
        
        #[cfg(miri)]
-       #[no_mangle]
+       #[unsafe(no_mangle)]
        fn miri_start(argc: isize, argv: *const *const u8) -> isize {
            // Call the actual start function that your project implements, based on your target's conventions.
        }
diff --git a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs
index 515e467fb54..ac6e221fcd8 100644
--- a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs
+++ b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs
@@ -9,6 +9,6 @@ extern "C" {
 fn main() {
     let mut fds = [-1, -1];
     let res = unsafe { pipe(fds.as_mut_ptr()) };
-    //~^ ERROR: calling a non-variadic function with a variadic caller-side signature
+    //~^ ERROR: ABI mismatch: calling a non-variadic function with a variadic caller-side signature
     assert_eq!(res, 0);
 }
diff --git a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr
index 2782f3b3269..0f642aca322 100644
--- a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr
+++ b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a non-variadic function with a variadic caller-side signature
+error: Undefined Behavior: ABI mismatch: calling a non-variadic function with a variadic caller-side signature
   --> tests/fail/shims/vararg_caller_signature_mismatch.rs:LL:CC
    |
 LL |     let res = unsafe { pipe(fds.as_mut_ptr()) };
-   |                        ^^^^^^^^^^^^^^^^^^^^^^ calling a non-variadic function with a variadic caller-side signature
+   |                        ^^^^^^^^^^^^^^^^^^^^^^ ABI mismatch: calling a non-variadic function with a variadic caller-side signature
    |
    = 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
diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
index a015464dbde..698ca4e0b4b 100644
--- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
@@ -2,6 +2,7 @@
 //@compile-flags: -Zmiri-disable-isolation
 #![allow(nonstandard_style)]
 
+use std::io::ErrorKind;
 use std::os::windows::ffi::OsStrExt;
 use std::path::Path;
 use std::ptr;
@@ -15,10 +16,10 @@ use windows_sys::Win32::Foundation::{
     STATUS_IO_DEVICE_ERROR,
 };
 use windows_sys::Win32::Storage::FileSystem::{
-    BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, FILE_ATTRIBUTE_DIRECTORY,
-    FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT,
-    FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS,
-    OPEN_EXISTING,
+    BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW,
+    FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS,
+    FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
+    GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING,
 };
 
 fn main() {
@@ -28,6 +29,7 @@ fn main() {
         test_create_always_twice();
         test_open_always_twice();
         test_open_dir_reparse();
+        test_delete_file();
         test_ntstatus_to_dos();
     }
 }
@@ -194,6 +196,21 @@ unsafe fn test_open_dir_reparse() {
     };
 }
 
+unsafe fn test_delete_file() {
+    let temp = utils::tmp().join("test_delete_file.txt");
+    let raw_path = to_wide_cstr(&temp);
+    let _ = std::fs::File::create(&temp).unwrap();
+
+    if DeleteFileW(raw_path.as_ptr()) == 0 {
+        panic!("Failed to delete file");
+    }
+
+    match std::fs::File::open(temp) {
+        Ok(_) => panic!("File not deleted"),
+        Err(e) => assert!(e.kind() == ErrorKind::NotFound, "File not deleted"),
+    }
+}
+
 unsafe fn test_ntstatus_to_dos() {
     // We won't test all combinations, just a couple common ones
     assert_eq!(RtlNtStatusToDosError(STATUS_IO_DEVICE_ERROR), ERROR_IO_DEVICE);
diff --git a/src/tools/miri/tests/pass/async-drop.rs b/src/tools/miri/tests/pass/async-drop.rs
index 2a95f644389..4fa84384d9b 100644
--- a/src/tools/miri/tests/pass/async-drop.rs
+++ b/src/tools/miri/tests/pass/async-drop.rs
@@ -10,10 +10,10 @@
 #![allow(incomplete_features, dead_code)]
 
 // FIXME(zetanumbers): consider AsyncDestruct::async_drop cleanup tests
-use core::future::{async_drop_in_place, AsyncDrop, Future};
+use core::future::{AsyncDrop, Future, async_drop_in_place};
 use core::hint::black_box;
 use core::mem::{self, ManuallyDrop};
-use core::pin::{pin, Pin};
+use core::pin::{Pin, pin};
 use core::task::{Context, Poll, Waker};
 
 async fn test_async_drop<T>(x: T) {
@@ -200,11 +200,7 @@ union AsyncUnion {
 
 impl Drop for AsyncUnion {
     fn drop(&mut self) {
-        println!(
-            "AsyncUnion::drop: {}, {}",
-            unsafe { self.signed },
-            unsafe { self.unsigned },
-        );
+        println!("AsyncUnion::drop: {}, {}", unsafe { self.signed }, unsafe { self.unsigned },);
     }
 }
 impl AsyncDrop for AsyncUnion {
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 6ad23055f30..d0a7f245ee0 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -17,10 +17,10 @@ mod utils;
 
 fn main() {
     test_path_conversion();
+    test_file_create_new();
     // Windows file handling is very incomplete.
     if cfg!(not(windows)) {
         test_file();
-        test_file_create_new();
         test_seek();
         test_file_clone();
         test_metadata();
diff --git a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs
new file mode 100644
index 00000000000..6dde593d2cf
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs
@@ -0,0 +1,178 @@
+//@revisions: default uniq
+//@compile-flags: -Zmiri-tree-borrows
+//@[uniq]compile-flags: -Zmiri-unique-is-unique
+#![allow(dangerous_implicit_autorefs)]
+use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
+use std::mem::{self, MaybeUninit};
+
+fn main() {
+    aliasing_mut_and_shr();
+    aliasing_frz_and_shr();
+    into_interior_mutability();
+    unsafe_cell_2phase();
+    unsafe_cell_deallocate();
+    unsafe_cell_invalidate();
+    refcell_basic();
+    ref_protector();
+    ref_mut_protector();
+    rust_issue_68303();
+}
+
+fn aliasing_mut_and_shr() {
+    fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
+        *aliasing += 4;
+        let _escape_to_raw = rc as *const _;
+        *aliasing += 4;
+        let _shr = &*rc;
+        *aliasing += 4;
+        // also turning this into a frozen ref now must work
+        let aliasing = &*aliasing;
+        let _val = *aliasing;
+        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
+        let _val = *aliasing;
+        let _shr = &*rc; // this must NOT unfreeze
+        let _val = *aliasing;
+    }
+
+    let rc = RefCell::new(23);
+    let mut bmut = rc.borrow_mut();
+    inner(&rc, &mut *bmut);
+    drop(bmut);
+    assert_eq!(*rc.borrow(), 23 + 12);
+}
+
+fn aliasing_frz_and_shr() {
+    fn inner(rc: &RefCell<i32>, aliasing: &i32) {
+        let _val = *aliasing;
+        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
+        let _val = *aliasing;
+        let _shr = &*rc; // this must NOT unfreeze
+        let _val = *aliasing;
+    }
+
+    let rc = RefCell::new(23);
+    let bshr = rc.borrow();
+    inner(&rc, &*bshr);
+    assert_eq!(*rc.borrow(), 23);
+}
+
+// Getting a pointer into a union with interior mutability used to be tricky
+// business (https://github.com/rust-lang/miri/issues/615), but it should work
+// now.
+fn into_interior_mutability() {
+    let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
+    x.as_ptr();
+    x.write((Cell::new(0), 1));
+    let ptr = unsafe { x.assume_init_ref() };
+    assert_eq!(ptr.1, 1);
+}
+
+// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
+// invalidate aliases.
+fn unsafe_cell_2phase() {
+    unsafe {
+        let x = &UnsafeCell::new(vec![]);
+        let x2 = &*x;
+        (*x.get()).push(0);
+        let _val = (*x2.get()).get(0);
+    }
+}
+
+/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call.
+/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.)
+fn unsafe_cell_deallocate() {
+    fn f(x: &UnsafeCell<i32>) {
+        let b: Box<i32> = unsafe { Box::from_raw(x as *const _ as *mut i32) };
+        drop(b)
+    }
+
+    let b = Box::new(0i32);
+    f(unsafe { mem::transmute(Box::into_raw(b)) });
+}
+
+/// As a side-effect of the above, we also allow this -- at least for now.
+fn unsafe_cell_invalidate() {
+    fn f(_x: &UnsafeCell<i32>, y: *mut i32) {
+        // Writing to y invalidates x, but that is okay.
+        unsafe {
+            *y += 1;
+        }
+    }
+
+    let mut x = 0i32;
+    let raw1 = &mut x as *mut _;
+    let ref1 = unsafe { &mut *raw1 };
+    let raw2 = ref1 as *mut _;
+    // Now the borrow stack is: raw1, ref2, raw2.
+    // So using raw1 invalidates raw2.
+    f(unsafe { mem::transmute(raw2) }, raw1);
+}
+
+fn refcell_basic() {
+    let c = RefCell::new(42);
+    {
+        let s1 = c.borrow();
+        let _x: i32 = *s1;
+        let s2 = c.borrow();
+        let _x: i32 = *s1;
+        let _y: i32 = *s2;
+        let _x: i32 = *s1;
+        let _y: i32 = *s2;
+    }
+    {
+        let mut m = c.borrow_mut();
+        let _z: i32 = *m;
+        {
+            let s: &i32 = &*m;
+            let _x = *s;
+        }
+        *m = 23;
+        let _z: i32 = *m;
+    }
+    {
+        let s1 = c.borrow();
+        let _x: i32 = *s1;
+        let s2 = c.borrow();
+        let _x: i32 = *s1;
+        let _y: i32 = *s2;
+        let _x: i32 = *s1;
+        let _y: i32 = *s2;
+    }
+}
+
+// Adding a Stacked Borrows protector for `Ref` would break this
+fn ref_protector() {
+    fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) {
+        // `r` has a shared reference, it is passed in as argument and hence
+        // a protector is added that marks this memory as read-only for the entire
+        // duration of this function.
+        drop(r);
+        // *oops* here we can mutate that memory.
+        *rc.borrow_mut() = 2;
+    }
+
+    let rc = RefCell::new(0);
+    break_it(&rc, rc.borrow())
+}
+
+fn ref_mut_protector() {
+    fn break_it(rc: &RefCell<i32>, r: RefMut<'_, i32>) {
+        // `r` has a shared reference, it is passed in as argument and hence
+        // a protector is added that marks this memory as inaccessible for the entire
+        // duration of this function
+        drop(r);
+        // *oops* here we can mutate that memory.
+        *rc.borrow_mut() = 2;
+    }
+
+    let rc = RefCell::new(0);
+    break_it(&rc, rc.borrow_mut())
+}
+
+/// Make sure we do not have bad enum layout optimizations.
+fn rust_issue_68303() {
+    let optional = Some(RefCell::new(false));
+    let mut handle = optional.as_ref().unwrap().borrow_mut();
+    assert!(optional.is_some());
+    *handle = true;
+}