Skip to content

Commit 95289c3

Browse files
committed
Auto merge of #104617 - RalfJung:miri, r=RalfJung
update Miri r? `@thomcc` for the lib changes (removing a `cfg(miri)` that is no longer needed)
2 parents 1de3c7c + 94ddca1 commit 95289c3

File tree

15 files changed

+152
-114
lines changed

15 files changed

+152
-114
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ doctest = false # and no doc tests
2121
getrandom = { version = "0.2", features = ["std"] }
2222
env_logger = "0.9"
2323
log = "0.4"
24-
shell-escape = "0.1.4"
2524
rand = "0.8"
2625
smallvec = "1.7"
2726

README.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
# Miri
22

3-
[![Actions build status][actions-badge]][actions-url]
4-
5-
[actions-badge]: https://github.com/rust-lang/miri/workflows/CI/badge.svg?branch=master
6-
[actions-url]: https://github.com/rust-lang/miri/actions
7-
83
An experimental interpreter for [Rust][rust]'s
94
[mid-level intermediate representation][mir] (MIR). It can run binaries and
105
test suites of cargo projects and detect certain classes of
@@ -200,7 +195,7 @@ randomness that is used to determine allocation base addresses. The following
200195
snippet calls Miri in a loop with different values for the seed:
201196

202197
```
203-
for SEED in $({ echo obase=16; seq 0 255; } | bc); do
198+
for SEED in $(seq 0 255); do
204199
echo "Trying seed: $SEED"
205200
MIRIFLAGS=-Zmiri-seed=$SEED cargo miri test || { echo "Failing seed: $SEED"; break; };
206201
done
@@ -308,7 +303,7 @@ environment variable. We first document the most relevant and most commonly used
308303
tell what it is doing when a program just keeps running. You can customize how frequently the
309304
report is printed via `-Zmiri-report-progress=<blocks>`, which prints the report every N basic
310305
blocks.
311-
* `-Zmiri-seed=<hex>` configures the seed of the RNG that Miri uses to resolve non-determinism. This
306+
* `-Zmiri-seed=<num>` configures the seed of the RNG that Miri uses to resolve non-determinism. This
312307
RNG is used to pick base addresses for allocations, to determine preemption and failure of
313308
`compare_exchange_weak`, and to control store buffering for weak memory emulation. When isolation
314309
is enabled (the default), this is also used to emulate system entropy. The default seed is 0. You

miri

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ Update and activate the rustup toolchain 'miri' to the commit given in the
4848
`rustup-toolchain-install-master` must be installed for this to work. Any extra
4949
flags are passed to `rustup-toolchain-install-master`.
5050
51-
./miri rustc-pull:
52-
Pull and merge Miri changes from the rustc repo. The fetched commit is stored in
53-
the `rust-version` file, so the next `./miri toolchain` will install the rustc
54-
we just pulled.
51+
./miri rustc-pull <commit>:
52+
Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest
53+
rustc commit. The fetched commit is stored in the `rust-version` file, so the
54+
next `./miri toolchain` will install the rustc that just got pulled.
5555
5656
./miri rustc-push <github user> <branch>:
5757
Push Miri changes back to the rustc repo. This will pull a copy of the rustc
@@ -113,18 +113,17 @@ toolchain)
113113
;;
114114
rustc-pull)
115115
cd "$MIRIDIR"
116-
FETCH_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1)
117-
# We can't pull from a commit with josh
118-
# (https://github.com/josh-project/josh/issues/1034), so we just hope that
119-
# nothing gets merged into rustc *during* this pull.
120-
git fetch http://localhost:8000/rust-lang/rust.git$JOSH_FILTER.git master
121-
# Just verify that `master` didn't move.
122-
if [[ $FETCH_COMMIT != $(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1) ]]; then
123-
echo "Looks like something got merged into Rust *while we were pulling*. Aborting. Please try again."
116+
FETCH_COMMIT="$1"
117+
if [ -z "$FETCH_COMMIT" ]; then
118+
FETCH_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1)
124119
fi
125-
echo "$FETCH_COMMIT" > rust-version # do this *before* merging as merging will fail in case of conflicts
120+
# Update rust-version file. As a separate commit, since making it part of
121+
# the merge has confused the heck out of josh in the past.
122+
echo "$FETCH_COMMIT" > rust-version
123+
git commit rust-version -m "Preparing for merge from rustc"
124+
# Fetch given rustc commit and note down which one that was
125+
git fetch http://localhost:8000/rust-lang/rust.git@$FETCH_COMMIT$JOSH_FILTER.git
126126
git merge FETCH_HEAD --no-ff -m "Merge from rustc"
127-
git commit rust-version --amend -m "Merge from rustc"
128127
exit 0
129128
;;
130129
rustc-push)
@@ -157,16 +156,27 @@ rustc-push)
157156
fi
158157
git fetch https://github.com/rust-lang/rust $BASE
159158
git push https://github.com/$USER/rust $BASE:refs/heads/$BRANCH -f
159+
echo
160160
# Do the actual push.
161161
cd "$MIRIDIR"
162162
echo "Pushing Miri changes..."
163163
git push http://localhost:8000/$USER/rust.git$JOSH_FILTER.git HEAD:$BRANCH
164-
exit 0
164+
# Do a round-trip check to make sure the push worked as expected.
165+
echo
166+
git fetch http://localhost:8000/$USER/rust.git@$JOSH_FILTER.git $BRANCH &>/dev/null
167+
if [[ $(git rev-parse HEAD) != $(git rev-parse FETCH_HEAD) ]]; then
168+
echo "ERROR: Josh created a non-roundtrip push! Do NOT merge this into rustc!"
169+
exit 1
170+
else
171+
echo "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
172+
echo " https://github.com/$USER/rust/pull/new/$BRANCH"
173+
exit 0
174+
fi
165175
;;
166176
many-seeds)
167-
for SEED in $({ echo obase=16; seq 0 255; } | bc); do
177+
for SEED in $(seq 0 255); do
168178
echo "Trying seed: $SEED"
169-
MIRIFLAGS="$MIRIFLAGS -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; }
179+
MIRIFLAGS="$MIRIFLAGS -Zlayout-seed=$SEED -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; }
170180
done
171181
exit 0
172182
;;

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
101e1822c3e54e63996c8aaa014d55716f3937eb
1+
7477c1f4f7d6bef037d523099b240d22aa1b63a0

src/bin/miri.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,9 @@ fn main() {
394394
if miri_config.seed.is_some() {
395395
show_error!("Cannot specify -Zmiri-seed multiple times!");
396396
}
397-
let seed = u64::from_str_radix(param, 16)
398-
.unwrap_or_else(|_| show_error!(
399-
"-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and must fit into a u64 (max 16 characters)"
400-
));
397+
let seed = param.parse::<u64>().unwrap_or_else(|_| {
398+
show_error!("-Zmiri-seed must be an integer that fits into u64")
399+
});
401400
miri_config.seed = Some(seed);
402401
} else if let Some(_param) = arg.strip_prefix("-Zmiri-env-exclude=") {
403402
show_error!(

src/shims/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8989
}
9090

9191
let ptr = this.read_pointer(ptr_op)?;
92+
// If this carries no provenance, treat it like an integer.
93+
if ptr.provenance.is_none() {
94+
// Use actual implementation.
95+
return Ok(false);
96+
}
97+
9298
if let Ok((alloc_id, _offset, _)) = this.ptr_try_get_alloc_id(ptr) {
9399
// Only do anything if we can identify the allocation this goes to.
94100
let (_size, cur_align, _kind) = this.get_alloc_info(alloc_id);

src/shims/time.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2222

2323
let this = self.eval_context_mut();
2424

25-
this.assert_target_os("linux", "clock_gettime");
25+
this.assert_target_os_is_unix("clock_gettime");
2626

2727
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
2828

29-
// Linux has two main kinds of clocks. REALTIME clocks return the actual time since the
30-
// Unix epoch, including effects which may cause time to move backwards such as NTP.
31-
// Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
32-
// is just specified to be "faster and less precise", so we implement both the same way.
33-
let absolute_clocks =
34-
[this.eval_libc_i32("CLOCK_REALTIME")?, this.eval_libc_i32("CLOCK_REALTIME_COARSE")?];
35-
// The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are
36-
// never allowed to go backwards. We don't need to do any additonal monotonicity
37-
// enforcement because std::time::Instant already guarantees that it is monotonic.
38-
let relative_clocks =
39-
[this.eval_libc_i32("CLOCK_MONOTONIC")?, this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?];
29+
let absolute_clocks;
30+
let mut relative_clocks;
31+
32+
match this.tcx.sess.target.os.as_ref() {
33+
"linux" => {
34+
// Linux has two main kinds of clocks. REALTIME clocks return the actual time since the
35+
// Unix epoch, including effects which may cause time to move backwards such as NTP.
36+
// Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
37+
// is just specified to be "faster and less precise", so we implement both the same way.
38+
absolute_clocks = vec![
39+
this.eval_libc_i32("CLOCK_REALTIME")?,
40+
this.eval_libc_i32("CLOCK_REALTIME_COARSE")?,
41+
];
42+
// The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are
43+
// never allowed to go backwards. We don't need to do any additonal monotonicity
44+
// enforcement because std::time::Instant already guarantees that it is monotonic.
45+
relative_clocks = vec![
46+
this.eval_libc_i32("CLOCK_MONOTONIC")?,
47+
this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?,
48+
];
49+
}
50+
"macos" => {
51+
absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")?];
52+
relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")?];
53+
// Some clocks only seem to exist in the aarch64 version of the target.
54+
if this.tcx.sess.target.arch == "aarch64" {
55+
// `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
56+
// that's not really something a program running inside Miri can tell, anyway.
57+
// We need to support it because std uses it.
58+
relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW")?);
59+
}
60+
}
61+
target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"),
62+
}
4063

4164
let duration = if absolute_clocks.contains(&clk_id) {
4265
this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?;
4366
system_time_to_duration(&SystemTime::now())?
4467
} else if relative_clocks.contains(&clk_id) {
4568
this.machine.clock.now().duration_since(this.machine.clock.anchor())
4669
} else {
70+
// Unsupported clock.
4771
let einval = this.eval_libc("EINVAL")?;
4872
this.set_last_error(einval)?;
4973
return Ok(Scalar::from_i32(-1));

src/shims/unix/foreign_items.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
180180
let result = this.gettimeofday(tv, tz)?;
181181
this.write_scalar(Scalar::from_i32(result), dest)?;
182182
}
183+
"clock_gettime" => {
184+
let [clk_id, tp] =
185+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
186+
let result = this.clock_gettime(clk_id, tp)?;
187+
this.write_scalar(result, dest)?;
188+
}
183189

184190
// Allocation
185191
"posix_memalign" => {

src/shims/unix/linux/foreign_items.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4343
this.write_scalar(result, dest)?;
4444
}
4545

46-
// Time related shims
47-
"clock_gettime" => {
48-
// This is a POSIX function but it has only been tested on linux.
49-
let [clk_id, tp] =
50-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
51-
let result = this.clock_gettime(clk_id, tp)?;
52-
this.write_scalar(result, dest)?;
53-
}
54-
5546
// Threading
5647
"pthread_condattr_setclock" => {
5748
let [attr, clock_id] =

src/stacked_borrows/mod.rs

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc_middle::mir::RetagKind;
1414
use rustc_middle::ty::{
1515
self,
1616
layout::{HasParamEnv, LayoutOf},
17-
Ty,
1817
};
1918
use rustc_target::abi::Abi;
2019
use rustc_target::abi::Size;
@@ -983,28 +982,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
983982
let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields };
984983
return visitor.visit_value(place);
985984

986-
// Determine mutability and whether to add a protector.
987-
// Cannot use `builtin_deref` because that reports *immutable* for `Box`,
988-
// making it useless.
989-
fn qualify(ty: Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> {
990-
match ty.kind() {
991-
// References are simple.
992-
ty::Ref(_, _, Mutability::Mut) =>
993-
Some((
994-
RefKind::Unique { two_phase: kind == RetagKind::TwoPhase },
995-
kind == RetagKind::FnEntry,
996-
)),
997-
ty::Ref(_, _, Mutability::Not) =>
998-
Some((RefKind::Shared, kind == RetagKind::FnEntry)),
999-
// Raw pointers need to be enabled.
1000-
ty::RawPtr(tym) if kind == RetagKind::Raw =>
1001-
Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)),
1002-
// Boxes are handled separately due to that allocator situation,
1003-
// see the visitor below.
1004-
_ => None,
1005-
}
1006-
}
1007-
1008985
// The actual visitor.
1009986
struct RetagVisitor<'ecx, 'mir, 'tcx> {
1010987
ecx: &'ecx mut MiriInterpCx<'mir, 'tcx>,
@@ -1057,34 +1034,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10571034
return Ok(());
10581035
}
10591036

1060-
let recurse_for_fields = || {
1061-
match self.retag_fields {
1062-
RetagFields::No => false,
1063-
RetagFields::Yes => true,
1064-
RetagFields::OnlyScalar => {
1065-
// Matching `ArgAbi::new` at the time of writing, only fields of
1066-
// `Scalar` and `ScalarPair` ABI are considered.
1067-
matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))
1037+
// Check the type of this value to see what to do with it (retag, or recurse).
1038+
match place.layout.ty.kind() {
1039+
ty::Ref(_, _, mutbl) => {
1040+
let ref_kind = match mutbl {
1041+
Mutability::Mut =>
1042+
RefKind::Unique { two_phase: self.kind == RetagKind::TwoPhase },
1043+
Mutability::Not => RefKind::Shared,
1044+
};
1045+
self.retag_place(
1046+
place,
1047+
ref_kind,
1048+
self.retag_cause,
1049+
/*protector*/ self.kind == RetagKind::FnEntry,
1050+
)?;
1051+
}
1052+
ty::RawPtr(tym) => {
1053+
// We definitely do *not* want to recurse into raw pointers -- wide raw
1054+
// pointers have fields, and for dyn Trait pointees those can have reference
1055+
// type!
1056+
if self.kind == RetagKind::Raw {
1057+
// Raw pointers need to be enabled.
1058+
self.retag_place(
1059+
place,
1060+
RefKind::Raw { mutable: tym.mutbl == Mutability::Mut },
1061+
self.retag_cause,
1062+
/*protector*/ false,
1063+
)?;
1064+
}
1065+
}
1066+
_ if place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) => {
1067+
// Recurse for boxes, they require some tricky handling and will end up in `visit_box` above.
1068+
// (Yes this means we technically also recursively retag the allocator itself
1069+
// even if field retagging is not enabled. *shrug*)
1070+
self.walk_value(place)?;
1071+
}
1072+
_ => {
1073+
// Not a reference/pointer/box. Only recurse if configured appropriately.
1074+
let recurse = match self.retag_fields {
1075+
RetagFields::No => false,
1076+
RetagFields::Yes => true,
1077+
RetagFields::OnlyScalar => {
1078+
// Matching `ArgAbi::new` at the time of writing, only fields of
1079+
// `Scalar` and `ScalarPair` ABI are considered.
1080+
matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))
1081+
}
1082+
};
1083+
if recurse {
1084+
self.walk_value(place)?;
10681085
}
10691086
}
1070-
};
1071-
1072-
if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) {
1073-
self.retag_place(place, ref_kind, self.retag_cause, protector)?;
1074-
} else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) {
1075-
// Wide raw pointers *do* have fields and their types are strange.
1076-
// vtables have a type like `&[*const (); 3]` or so!
1077-
// Do *not* recurse into them.
1078-
// (No need to worry about wide references, those always "qualify". And Boxes
1079-
// are handles specially by the visitor anyway.)
1080-
} else if recurse_for_fields()
1081-
|| place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box())
1082-
{
1083-
// Recurse deeper. Need to always recurse for `Box` to even hit `visit_box`.
1084-
// (Yes this means we technically also recursively retag the allocator itself
1085-
// even if field retagging is not enabled. *shrug*)
1086-
self.walk_value(place)?;
10871087
}
1088+
10881089
Ok(())
10891090
}
10901091
}

test-cargo-miri/run-test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def test_cargo_miri_test():
133133
test("`cargo miri test`",
134134
cargo_miri("test"),
135135
default_ref, "test.stderr-empty.ref",
136-
env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=feed"},
136+
env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=4242"},
137137
)
138138
test("`cargo miri test` (no isolation, no doctests)",
139139
cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml`

0 commit comments

Comments
 (0)