Auto merge of #113488 - RalfJung:miri, r=RalfJung

update Miri
This commit is contained in:
bors 2023-07-09 13:37:41 +00:00
commit b12ff66f2c
33 changed files with 253 additions and 100 deletions

View File

@ -5406,9 +5406,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]] [[package]]
name = "ui_test" name = "ui_test"
version = "0.11.6" version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a2e70adc9d18b9b4dd80ea57aeec447103c6fbb354a07c080adad451c645e1" checksum = "c21899b59f53717dfad29e4f46e5b21a200a1b6888ab86532a07cfc8b48dd78c"
dependencies = [ dependencies = [
"bstr", "bstr",
"cargo-platform", "cargo-platform",

View File

@ -15,6 +15,10 @@ on:
env: env:
CARGO_UNSTABLE_SPARSE_REGISTRY: 'true' CARGO_UNSTABLE_SPARSE_REGISTRY: 'true'
defaults:
run:
shell: bash
jobs: jobs:
build: build:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@ -59,12 +63,9 @@ jobs:
- name: Install rustup-toolchain-install-master - name: Install rustup-toolchain-install-master
if: ${{ steps.cache.outputs.cache-hit != 'true' }} if: ${{ steps.cache.outputs.cache-hit != 'true' }}
shell: bash run: cargo install -f rustup-toolchain-install-master
run: |
cargo install -f rustup-toolchain-install-master
- name: Install "master" toolchain - name: Install "master" toolchain
shell: bash
run: | run: |
if [[ ${{ github.event_name }} == 'schedule' ]]; then if [[ ${{ github.event_name }} == 'schedule' ]]; then
echo "Building against latest rustc git version" echo "Building against latest rustc git version"
@ -79,7 +80,7 @@ jobs:
cargo -V cargo -V
- name: Test - name: Test
run: bash ./ci.sh run: ./ci.sh
style: style:
name: style checks name: style checks
@ -111,14 +112,10 @@ jobs:
- name: Install rustup-toolchain-install-master - name: Install rustup-toolchain-install-master
if: ${{ steps.cache.outputs.cache-hit != 'true' }} if: ${{ steps.cache.outputs.cache-hit != 'true' }}
shell: bash run: cargo install -f rustup-toolchain-install-master
run: |
cargo install -f rustup-toolchain-install-master
- name: Install "master" toolchain - name: Install "master" toolchain
shell: bash run: ./miri toolchain
run: |
./miri toolchain
- name: Show Rust version - name: Show Rust version
run: | run: |
@ -138,7 +135,6 @@ jobs:
# workflow is successful listening to webhooks only. # workflow is successful listening to webhooks only.
# #
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
# (`fmt` is deliberately not listed, we want bors to ignore it.)
end-success: end-success:
name: bors build finished name: bors build finished
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -166,12 +162,12 @@ jobs:
- name: Install zulip-send - name: Install zulip-send
run: pip3 install zulip run: pip3 install zulip
- name: Send Zulip notification - name: Send Zulip notification
shell: bash
env: env:
ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
run: | run: |
~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
--stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
--message 'Dear @*T-miri*, --message 'Dear @*T-miri*,
It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed. It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed.
@ -183,9 +179,12 @@ jobs:
Thanks in advance! Thanks in advance!
Sincerely, Sincerely,
The Miri Cronjobs Bot' \ The Miri Cronjobs Bot'
--user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com
# Attempt to auto-sync with rustc # Attempt to auto-sync with rustc
- uses: actions/checkout@v3
with:
fetch-depth: 256 # get a bit more of the history
- name: install josh-proxy - name: install josh-proxy
run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06 run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06
- name: start josh-proxy - name: start josh-proxy
@ -196,16 +195,24 @@ jobs:
git config --global user.email 'miri@cron.bot' git config --global user.email 'miri@cron.bot'
- name: get changes from rustc - name: get changes from rustc
run: ./miri rustc-pull run: ./miri rustc-pull
- name: Install rustup-toolchain-install-master
run: cargo install -f rustup-toolchain-install-master
- name: format changes (if any) - name: format changes (if any)
run: | run: |
./miri toolchain ./miri toolchain
./miri fmt --check || (./miri fmt && git commit -am "fmt") ./miri fmt --check || (./miri fmt && git commit -am "fmt")
- name: Push changes to a branch - name: Push changes to a branch
run: | run: |
git switch -c "rustup$(date -u +%Y-%m)" BRANCH="rustup$(date -u +%Y-%m-%d)"
git push git switch -c $BRANCH
git push -u origin $BRANCH
- name: Create Pull Request - name: Create Pull Request
run: gh pr create -B master --title 'Automatic sync from rustc' --body '' run: |
PR=$(gh pr create -B master --title 'Automatic sync from rustc' --body '')
~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
--stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
--message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}

View File

@ -842,9 +842,9 @@ dependencies = [
[[package]] [[package]]
name = "ui_test" name = "ui_test"
version = "0.11.6" version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a2e70adc9d18b9b4dd80ea57aeec447103c6fbb354a07c080adad451c645e1" checksum = "c21899b59f53717dfad29e4f46e5b21a200a1b6888ab86532a07cfc8b48dd78c"
dependencies = [ dependencies = [
"bstr", "bstr",
"cargo-platform", "cargo-platform",

View File

@ -36,7 +36,7 @@ libloading = "0.7"
[dev-dependencies] [dev-dependencies]
colored = "2" colored = "2"
ui_test = "0.11.6" ui_test = "0.11.7"
rustc_version = "0.4" rustc_version = "0.4"
# Features chosen to match those required by env_logger, to avoid rebuilds # Features chosen to match those required by env_logger, to avoid rebuilds
regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] }

View File

@ -80,7 +80,11 @@ fn main() {
match first.as_str() { match first.as_str() {
"miri" => phase_cargo_miri(args), "miri" => phase_cargo_miri(args),
"runner" => phase_runner(args, RunnerPhase::Cargo), "runner" => phase_runner(args, RunnerPhase::Cargo),
arg if arg == env::var("RUSTC").unwrap() => { arg if arg == env::var("RUSTC").unwrap_or_else(|_| {
show_error!(
"`cargo-miri` called without RUSTC set; please only invoke this binary through `cargo miri`"
)
}) => {
// If the first arg is equal to the RUSTC env variable (which should be set at this // If the first arg is equal to the RUSTC env variable (which should be set at this
// point), then we need to behave as rustc. This is the somewhat counter-intuitive // point), then we need to behave as rustc. This is the somewhat counter-intuitive
// behavior of having both RUSTC and RUSTC_WRAPPER set // behavior of having both RUSTC and RUSTC_WRAPPER set

View File

@ -82,7 +82,7 @@ pub enum MiriCommand {
pub fn escape_for_toml(s: &str) -> String { pub fn escape_for_toml(s: &str) -> String {
// We want to surround this string in quotes `"`. So we first escape all quotes, // We want to surround this string in quotes `"`. So we first escape all quotes,
// and also all backslashes (that are used to escape quotes). // and also all backslashes (that are used to escape quotes).
let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); let s = s.replace('\\', r"\\").replace('"', r#"\""#);
format!("\"{s}\"") format!("\"{s}\"")
} }
@ -130,7 +130,7 @@ pub fn exec(mut cmd: Command) -> ! {
{ {
use std::os::unix::process::CommandExt; use std::os::unix::process::CommandExt;
let error = cmd.exec(); let error = cmd.exec();
Err(error).expect("failed to run command") panic!("failed to run command: {error}")
} }
} }

View File

@ -124,7 +124,7 @@ rustc-pull)
git commit rust-version -m "Preparing for merge from rustc" || (echo "FAILED to commit rust-version file, something went wrong"; exit 1) git commit rust-version -m "Preparing for merge from rustc" || (echo "FAILED to commit rust-version file, something went wrong"; exit 1)
# Fetch given rustc commit and note down which one that was # Fetch given rustc commit and note down which one that was
git fetch http://localhost:8000/rust-lang/rust.git@$FETCH_COMMIT$JOSH_FILTER.git || (echo "FAILED to fetch new commits, something went wrong"; exit 1) git fetch http://localhost:8000/rust-lang/rust.git@$FETCH_COMMIT$JOSH_FILTER.git || (echo "FAILED to fetch new commits, something went wrong"; exit 1)
git merge FETCH_HEAD --no-ff -m "Merge from rustc" || (echo "FAILED to merge new commits, something went wrong"; exit 1) git merge FETCH_HEAD --no-ff -m "Merge from rustc" || (echo "FAILED to merge new commits ($(git rev-parse FETCH_HEAD)), something went wrong"; exit 1)
exit 0 exit 0
;; ;;
rustc-push) rustc-push)
@ -325,6 +325,7 @@ run|run-dep)
MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET" MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET"
fi fi
CARGO="$CARGO --quiet"
# First build and get a sysroot. # First build and get a sysroot.
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
find_sysroot find_sysroot

View File

@ -1 +1 @@
75726cae37317c7262b69d3e9fd11a3496a88d04 d4096e0412ac5de785d739a0aa2b1c1c7b9d3b7d

View File

@ -67,7 +67,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
if tcx.sess.compile_status().is_err() { if tcx.sess.compile_status().is_err() {
tcx.sess.fatal("miri cannot be run on programs that fail compilation"); tcx.sess.fatal("miri cannot be run on programs that fail compilation");
} }
;
init_late_loggers(handler, tcx); init_late_loggers(handler, tcx);
if !tcx.sess.crate_types().contains(&CrateType::Executable) { if !tcx.sess.crate_types().contains(&CrateType::Executable) {
tcx.sess.fatal("miri only makes sense on bin crates"); tcx.sess.fatal("miri only makes sense on bin crates");

View File

@ -221,7 +221,10 @@ impl AllocHistory {
impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> { impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
pub fn start_grant(&mut self, perm: Permission) { pub fn start_grant(&mut self, perm: Permission) {
let Operation::Retag(op) = &mut self.operation else { let Operation::Retag(op) = &mut self.operation else {
unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation) unreachable!(
"start_grant must only be called during a retag, this is: {:?}",
self.operation
)
}; };
op.permission = Some(perm); op.permission = Some(perm);
@ -286,7 +289,8 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
tag: BorTag, tag: BorTag,
protector_tag: Option<BorTag>, protector_tag: Option<BorTag>,
) -> Option<TagHistory> { ) -> Option<TagHistory> {
let Some(created) = self.history let Some(created) = self
.history
.creations .creations
.iter() .iter()
.rev() .rev()
@ -315,22 +319,27 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
None None
} }
}) })
}).or_else(|| { })
.or_else(|| {
// If we didn't find a retag that created this tag, it might be the base tag of // If we didn't find a retag that created this tag, it might be the base tag of
// this allocation. // this allocation.
if self.history.base.0.tag() == tag { if self.history.base.0.tag() == tag {
Some(( Some((
format!("{tag:?} was created here, as the base tag for {:?}", self.history.id), format!(
self.history.base.1.data() "{tag:?} was created here, as the base tag for {:?}",
self.history.id
),
self.history.base.1.data(),
)) ))
} else { } else {
None None
} }
}) else { })
// But if we don't have a creation event, this is related to a wildcard, and there else {
// is really nothing we can do to help. // But if we don't have a creation event, this is related to a wildcard, and there
return None; // is really nothing we can do to help.
}; return None;
};
let invalidated = self.history.invalidations.iter().rev().find_map(|event| { let invalidated = self.history.invalidations.iter().rev().find_map(|event| {
if event.tag == tag { Some(event.generate_diagnostic()) } else { None } if event.tag == tag { Some(event.generate_diagnostic()) } else { None }

View File

@ -430,12 +430,15 @@ impl<'tcx> Stack {
.find_granting(AccessKind::Write, derived_from, exposed_tags) .find_granting(AccessKind::Write, derived_from, exposed_tags)
.map_err(|()| dcx.grant_error(self))?; .map_err(|()| dcx.grant_error(self))?;
let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else { let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from)
else {
// The parent is a wildcard pointer or matched the unknown bottom. // The parent is a wildcard pointer or matched the unknown bottom.
// This is approximate. Nobody knows what happened, so forget everything. // This is approximate. Nobody knows what happened, so forget everything.
// The new thing is SRW anyway, so we cannot push it "on top of the unknown part" // The new thing is SRW anyway, so we cannot push it "on top of the unknown part"
// (for all we know, it might join an SRW group inside the unknown). // (for all we know, it might join an SRW group inside the unknown).
trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); trace!(
"reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"
);
self.set_unknown_bottom(global.next_ptr_tag); self.set_unknown_bottom(global.next_ptr_tag);
return Ok(()); return Ok(());
}; };
@ -1008,7 +1011,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// We have to turn the place into a pointer to use the existing code. // We have to turn the place into a pointer to use the existing code.
// (The pointer type does not matter, so we use a raw pointer.) // (The pointer type does not matter, so we use a raw pointer.)
let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?; let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?;
let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
// Reborrow it. With protection! That is part of the point. // Reborrow it. With protection! That is part of the point.
let new_perm = NewPermission::Uniform { let new_perm = NewPermission::Uniform {

View File

@ -196,19 +196,19 @@ impl<'tcx> Stack {
let ProvenanceExtra::Concrete(tag) = tag else { let ProvenanceExtra::Concrete(tag) = tag else {
// Handle the wildcard case. // Handle the wildcard case.
// Go search the stack for an exposed tag. // Go search the stack for an exposed tag.
if let Some(idx) = if let Some(idx) = self
self.borrows .borrows
.iter() .iter()
.enumerate() // we also need to know *where* in the stack .enumerate() // we also need to know *where* in the stack
.rev() // search top-to-bottom .rev() // search top-to-bottom
.find_map(|(idx, item)| { .find_map(|(idx, item)| {
// If the item fits and *might* be this wildcard, use it. // If the item fits and *might* be this wildcard, use it.
if item.perm().grants(access) && exposed_tags.contains(&item.tag()) { if item.perm().grants(access) && exposed_tags.contains(&item.tag()) {
Some(idx) Some(idx)
} else { } else {
None None
} }
}) })
{ {
return Ok(Some(idx)); return Ok(Some(idx));
} }

View File

@ -570,9 +570,13 @@ impl DisplayRepr {
extraction_aux(tree, tree.root, show_unnamed, &mut v); extraction_aux(tree, tree.root, show_unnamed, &mut v);
let Some(root) = v.pop() else { let Some(root) = v.pop() else {
if show_unnamed { if show_unnamed {
unreachable!("This allocation contains no tags, not even a root. This should not happen."); unreachable!(
"This allocation contains no tags, not even a root. This should not happen."
);
} }
eprintln!("This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."); eprintln!(
"This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."
);
return None; return None;
}; };
assert!(v.is_empty()); assert!(v.is_empty());

View File

@ -256,7 +256,9 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
ptr_size.bytes() ptr_size.bytes()
); );
let Some(new_perm) = new_perm else { return Ok(Some((alloc_id, orig_tag))); }; let Some(new_perm) = new_perm else {
return Ok(Some((alloc_id, orig_tag)));
};
if let Some(protect) = new_perm.protector { if let Some(protect) = new_perm.protector {
// We register the protection in two different places. // We register the protection in two different places.
@ -509,7 +511,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// We have to turn the place into a pointer to use the existing code. // We have to turn the place into a pointer to use the existing code.
// (The pointer type does not matter, so we use a raw pointer.) // (The pointer type does not matter, so we use a raw pointer.)
let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?; let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?;
let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
// Reborrow it. With protection! That is part of the point. // Reborrow it. With protection! That is part of the point.
// FIXME: do we truly want a 2phase borrow here? // FIXME: do we truly want a 2phase borrow here?

View File

@ -305,7 +305,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
for arg in config.args.iter() { for arg in config.args.iter() {
// Make space for `0` terminator. // Make space for `0` terminator.
let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap();
let arg_type = Ty::new_array(tcx,tcx.types.u8, size); let arg_type = Ty::new_array(tcx, tcx.types.u8, size);
let arg_place = let arg_place =
ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?;
ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
@ -313,9 +313,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
argvs.push(arg_place.to_ref(&ecx)); argvs.push(arg_place.to_ref(&ecx));
} }
// Make an array with all these pointers, in the Miri memory. // Make an array with all these pointers, in the Miri memory.
let argvs_layout = ecx.layout_of( let argvs_layout = ecx.layout_of(Ty::new_array(
Ty::new_array(tcx,Ty::new_imm_ptr(tcx,tcx.types.u8), u64::try_from(argvs.len()).unwrap()), tcx,
)?; Ty::new_imm_ptr(tcx, tcx.types.u8),
u64::try_from(argvs.len()).unwrap(),
))?;
let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
for (idx, arg) in argvs.into_iter().enumerate() { for (idx, arg) in argvs.into_iter().enumerate() {
let place = ecx.mplace_field(&argvs_place, idx)?; let place = ecx.mplace_field(&argvs_place, idx)?;
@ -333,7 +335,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
ecx.machine.argc = Some(*argc_place); ecx.machine.argc = Some(*argc_place);
let argv_place = ecx.allocate( let argv_place = ecx.allocate(
ecx.layout_of(Ty::new_imm_ptr(tcx,tcx.types.unit))?, ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?,
MiriMemoryKind::Machine.into(), MiriMemoryKind::Machine.into(),
)?; )?;
ecx.write_immediate(argv, &argv_place.into())?; ecx.write_immediate(argv, &argv_place.into())?;
@ -345,7 +347,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
// Construct a command string with all the arguments. // Construct a command string with all the arguments.
let cmd_utf16: Vec<u16> = args_to_utf16_command_string(config.args.iter()); let cmd_utf16: Vec<u16> = args_to_utf16_command_string(config.args.iter());
let cmd_type = Ty::new_array(tcx,tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_type =
Ty::new_array(tcx, tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
let cmd_place = let cmd_place =
ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?;
ecx.machine.cmd_line = Some(*cmd_place); ecx.machine.cmd_line = Some(*cmd_place);
@ -366,7 +369,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
match entry_type { match entry_type {
EntryFnType::Main { .. } => { EntryFnType::Main { .. } => {
let start_id = tcx.lang_items().start_fn().unwrap(); let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| {
tcx.sess.fatal(
"could not find start function. Make sure the entry point is marked with `#[start]`."
);
});
let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output(); let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
let start_instance = ty::Instance::resolve( let start_instance = ty::Instance::resolve(

View File

@ -9,6 +9,7 @@
#![feature(local_key_cell_methods)] #![feature(local_key_cell_methods)]
#![feature(round_ties_even)] #![feature(round_ties_even)]
#![feature(os_str_bytes)] #![feature(os_str_bytes)]
#![feature(lint_reasons)]
// Configure clippy and other lints // Configure clippy and other lints
#![allow( #![allow(
clippy::collapsible_else_if, clippy::collapsible_else_if,

View File

@ -313,10 +313,12 @@ pub struct PrimitiveLayouts<'tcx> {
impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> {
let tcx = layout_cx.tcx; let tcx = layout_cx.tcx;
let mut_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); let mut_raw_ptr =
let const_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
let const_raw_ptr =
Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
Ok(Self { Ok(Self {
unit: layout_cx.layout_of(Ty::new_unit(tcx,))?, unit: layout_cx.layout_of(Ty::new_unit(tcx))?,
i8: layout_cx.layout_of(tcx.types.i8)?, i8: layout_cx.layout_of(tcx.types.i8)?,
i16: layout_cx.layout_of(tcx.types.i16)?, i16: layout_cx.layout_of(tcx.types.i16)?,
i32: layout_cx.layout_of(tcx.types.i32)?, i32: layout_cx.layout_of(tcx.types.i32)?,

View File

@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let len: u64 = ptrs.len().try_into().unwrap(); let len: u64 = ptrs.len().try_into().unwrap();
let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
let array_layout = this.layout_of(Ty::new_array(tcx.tcx,ptr_ty, len)).unwrap(); let array_layout = this.layout_of(Ty::new_array(tcx.tcx, ptr_ty, len)).unwrap();
match flags { match flags {
// storage for pointers is allocated by miri // storage for pointers is allocated by miri

View File

@ -5,8 +5,8 @@ use std::mem;
use rustc_const_eval::interpret::Pointer; use rustc_const_eval::interpret::Pointer;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::Ty;
use rustc_target::abi::Size; use rustc_target::abi::Size;
use crate::helpers::target_os_is_unix; use crate::helpers::target_os_is_unix;
@ -449,9 +449,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
vars.push(Pointer::null()); vars.push(Pointer::null());
// Make an array with all these pointers inside Miri. // Make an array with all these pointers inside Miri.
let tcx = this.tcx; let tcx = this.tcx;
let vars_layout = this.layout_of( let vars_layout = this.layout_of(Ty::new_array(
Ty::new_array(tcx.tcx,this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()), tcx.tcx,
)?; this.machine.layouts.mut_raw_ptr.ty,
u64::try_from(vars.len()).unwrap(),
))?;
let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
for (idx, var) in vars.into_iter().enumerate() { for (idx, var) in vars.into_iter().enumerate() {
let place = this.mplace_field(&vars_place, idx)?; let place = this.mplace_field(&vars_place, idx)?;

View File

@ -763,6 +763,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_dest = this.read_pointer(ptr_dest)?;
let ptr_src = this.read_pointer(ptr_src)?; let ptr_src = this.read_pointer(ptr_src)?;
let n = this.read_target_usize(n)?; let n = this.read_target_usize(n)?;
// C requires that this must always be a valid pointer, even if `n` is zero, so we better check that.
// (This is more than Rust requires, so `mem_copy` is not sufficient.)
this.ptr_get_alloc_id(ptr_dest)?;
this.ptr_get_alloc_id(ptr_src)?;
this.mem_copy( this.mem_copy(
ptr_src, ptr_src,
Align::ONE, Align::ONE,

View File

@ -483,7 +483,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// `index` is an array, not a SIMD type // `index` is an array, not a SIMD type
let ty::Array(_, index_len) = index.layout.ty.kind() else { let ty::Array(_, index_len) = index.layout.ty.kind() else {
span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) span_bug!(
this.cur_span(),
"simd_shuffle index argument has non-array type {}",
index.layout.ty
)
}; };
let index_len = index_len.eval_target_usize(*this.tcx, this.param_env()); let index_len = index_len.eval_target_usize(*this.tcx, this.param_env());
@ -622,9 +626,7 @@ fn fmax_op<'tcx>(
right: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> { ) -> InterpResult<'tcx, Scalar<Provenance>> {
assert_eq!(left.layout.ty, right.layout.ty); assert_eq!(left.layout.ty, right.layout.ty);
let ty::Float(float_ty) = left.layout.ty.kind() else { let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmax operand is not a float") };
bug!("fmax operand is not a float")
};
let left = left.to_scalar(); let left = left.to_scalar();
let right = right.to_scalar(); let right = right.to_scalar();
Ok(match float_ty { Ok(match float_ty {
@ -638,9 +640,7 @@ fn fmin_op<'tcx>(
right: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> { ) -> InterpResult<'tcx, Scalar<Provenance>> {
assert_eq!(left.layout.ty, right.layout.ty); assert_eq!(left.layout.ty, right.layout.ty);
let ty::Float(float_ty) = left.layout.ty.kind() else { let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmin operand is not a float") };
bug!("fmin operand is not a float")
};
let left = left.to_scalar(); let left = left.to_scalar();
let right = right.to_scalar(); let right = right.to_scalar();
Ok(match float_ty { Ok(match float_ty {

View File

@ -7,8 +7,8 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt};
#[cfg(windows)] #[cfg(windows)]
use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::os::windows::ffi::{OsStrExt, OsStringExt};
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::Ty;
use crate::*; use crate::*;
@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator.
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u8, size); let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u8, size);
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
assert!(written); assert!(written);
@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator.
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u16, size); let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size);
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
let (written, _) = let (written, _) =
self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap(); self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap();

View File

@ -181,6 +181,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics. /// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics.
/// ///
/// <https://linux.die.net/man/2/eventfd> /// <https://linux.die.net/man/2/eventfd>
#[expect(clippy::needless_if)]
fn eventfd( fn eventfd(
&mut self, &mut self,
val: &OpTy<'tcx, Provenance>, val: &OpTy<'tcx, Provenance>,

View File

@ -145,7 +145,8 @@ fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> R
// The files we're actually interested in (all `.rs` files). // The files we're actually interested in (all `.rs` files).
|path| { |path| {
path.extension().is_some_and(|ext| ext == "rs") path.extension().is_some_and(|ext| ext == "rs")
&& (filters.is_empty() || filters.iter().any(|f| path.starts_with(f))) && (filters.is_empty()
|| filters.iter().any(|f| path.display().to_string().contains(f)))
}, },
// This could be used to overwrite the `Config` on a per-test basis. // This could be used to overwrite the `Config` on a per-test basis.
|_, _| None, |_, _| None,
@ -274,13 +275,13 @@ fn main() -> Result<()> {
fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> { fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> {
let path = args.next().expect("./miri run-dep must be followed by a file name"); let path = args.next().expect("./miri run-dep must be followed by a file name");
let mut config = test_config(&target, "", Mode::Yolo, /* with dependencies */ true); let mut config = test_config(&target, "", Mode::Yolo, /* with dependencies */ true);
config.program.args.remove(0); // remove the `--error-format=json` argument config.program.args.clear(); // We want to give the user full control over flags
config.program.args.push("--color".into()); config.build_dependencies_and_link_them()?;
config.program.args.push("always".into());
let mut cmd = ui_test::test_command(config, Path::new(&path))?; let mut cmd = config.program.build(&config.out_dir);
// Separate the arguments to the `cargo miri` invocation from
// the arguments to the interpreted prog cmd.arg(path);
cmd.arg("--");
cmd.args(args); cmd.args(args);
if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) } if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) }
} }

View File

@ -0,0 +1,10 @@
//@ignore-target-windows: No libc on Windows
use std::ptr;
// null is explicitly called out as UB in the C docs.
fn main() {
unsafe {
libc::memchr(ptr::null(), 0, 0); //~ERROR: dangling
}
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
--> $DIR/memchr_null.rs:LL:CC
|
LL | libc::memchr(ptr::null(), 0, 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/memchr_null.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -0,0 +1,10 @@
//@ignore-target-windows: No libc on Windows
use std::ptr;
// null is explicitly called out as UB in the C docs.
fn main() {
unsafe {
libc::memcmp(ptr::null(), ptr::null(), 0); //~ERROR: dangling
}
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
--> $DIR/memcmp_null.rs:LL:CC
|
LL | libc::memcmp(ptr::null(), ptr::null(), 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/memcmp_null.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -0,0 +1,12 @@
//@ignore-target-windows: No libc on Windows
//@compile-flags: -Zmiri-permissive-provenance
// C's memcpy is 0 bytes is UB for some pointers that are allowed in Rust's `copy_nonoverlapping`.
fn main() {
let from = 42 as *const u8;
let to = 23 as *mut u8;
unsafe {
to.copy_from(from, 0); // this is fine
libc::memcpy(to.cast(), from.cast(), 0); //~ERROR: dangling
}
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance)
--> $DIR/memcpy_zero.rs:LL:CC
|
LL | libc::memcpy(to.cast(), from.cast(), 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/memcpy_zero.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -0,0 +1,11 @@
//@ignore-target-windows: No libc on Windows
//@ignore-target-apple: No `memrchr` on some apple targets
use std::ptr;
// null is explicitly called out as UB in the C docs.
fn main() {
unsafe {
libc::memrchr(ptr::null(), 0, 0); //~ERROR: dangling
}
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
--> $DIR/memrchr_null.rs:LL:CC
|
LL | libc::memrchr(ptr::null(), 0, 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/memrchr_null.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -100,7 +100,7 @@ fn vec_push_ptr_stable() {
v.push(0); v.push(0);
let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
v.push(1); v.push(1);
let _val = *v0; *v0 = *v0;
} }
fn vec_extend_ptr_stable() { fn vec_extend_ptr_stable() {
@ -109,23 +109,23 @@ fn vec_extend_ptr_stable() {
let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
// `slice::Iter` (with `T: Copy`) specialization // `slice::Iter` (with `T: Copy`) specialization
v.extend(&[1]); v.extend(&[1]);
let _val = *v0; *v0 = *v0;
// `vec::IntoIter` specialization // `vec::IntoIter` specialization
v.extend(vec![2]); v.extend(vec![2]);
let _val = *v0; *v0 = *v0;
// `TrustedLen` specialization // `TrustedLen` specialization
v.extend(std::iter::once(3)); v.extend(std::iter::once(3));
let _val = *v0; *v0 = *v0;
// base case // base case
v.extend(std::iter::once(3).filter(|_| true)); v.extend(std::iter::once(3).filter(|_| true));
let _val = *v0; *v0 = *v0;
} }
fn vec_truncate_ptr_stable() { fn vec_truncate_ptr_stable() {
let mut v = vec![0; 10]; let mut v = vec![0; 10];
let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
v.truncate(5); v.truncate(5);
let _val = *v0; *v0 = *v0;
} }
fn push_str_ptr_stable() { fn push_str_ptr_stable() {