Skip to content

Miri subtree update #118022

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b7a98e3
freebsd adding getentropy interception support
devnexen Nov 12, 2023
382475d
Auto merge of #3161 - devnexen:freebsd_upd2, r=RalfJung
bors Nov 13, 2023
6e907fa
organize pass-dep tests more by the crate they test
RalfJung Nov 13, 2023
edb4c0a
share getentropy shim across various unixes
RalfJung Nov 13, 2023
2832253
Auto merge of #3162 - RalfJung:random, r=RalfJung
bors Nov 13, 2023
9840525
don't expose all the borrow tracker stuff to the entire crate
RalfJung Nov 13, 2023
177d8f2
Auto merge of #3163 - RalfJung:borrow-privacy, r=RalfJung
bors Nov 13, 2023
39e142f
Preparing for merge from rustc
Nov 15, 2023
34e8340
Merge from rustc
Nov 15, 2023
31e62a9
Auto merge of #3165 - rust-lang:rustup-2023-11-15, r=RalfJung
bors Nov 15, 2023
c3fd57d
freebsd adding getrandom interception.
devnexen Nov 13, 2023
012bd49
Auto merge of #3164 - devnexen:fbsd_upd3, r=RalfJung
bors Nov 15, 2023
9c8c2d1
Preparing for merge from rustc
RalfJung Nov 16, 2023
13bfe14
Merge from rustc
RalfJung Nov 16, 2023
255d04c
Auto merge of #3167 - RalfJung:rustup, r=RalfJung
bors Nov 16, 2023
ca67d7f
get rid of our last uses of set_var
RalfJung Nov 16, 2023
7df74eb
Auto merge of #3168 - RalfJung:set_var, r=RalfJung
bors Nov 16, 2023
c6acc05
reallocarray shim linux/freebsd support proposal.
devnexen Nov 15, 2023
0b6b44f
Auto merge of #3166 - devnexen:reallocarray, r=RalfJung
bors Nov 16, 2023
7338c55
split thread test into synchronization primitives and threadname
RalfJung Nov 16, 2023
6985431
make libc-misc pass under FreeBSD
RalfJung Nov 16, 2023
70cc639
move reallocarray test into libc-misc
RalfJung Nov 16, 2023
8edb0ad
actually all the 'env' tests work on FreeBSD, as well as posix_memalign
RalfJung Nov 16, 2023
3d65927
Auto merge of #3170 - RalfJung:libc-tests, r=RalfJung
bors Nov 16, 2023
b7c2745
Preparing for merge from rustc
saethlin Nov 16, 2023
a5a039b
Merge from rustc
saethlin Nov 16, 2023
ee48a3f
Auto merge of #3171 - saethlin:rustup, r=saethlin
bors Nov 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/tools/miri/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ case $HOST_TARGET in
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthreads atomic env/var
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc atomic env align
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3aaa0f57b7b877ef58532a8de075d1e5a79142bf
820f06b21f8373060ff7b515715b8440a6a6c197
58 changes: 45 additions & 13 deletions src/tools/miri/src/borrow_tracker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl fmt::Debug for BorTag {
#[derive(Debug)]
pub struct FrameState {
/// The ID of the call this frame corresponds to.
pub call_id: CallId,
call_id: CallId,

/// If this frame is protecting any tags, they are listed here. We use this list to do
/// incremental updates of the global list of protected tags stored in the
Expand All @@ -72,7 +72,7 @@ pub struct FrameState {
///
/// This will contain one tag per reference passed to the function, so
/// a size of 2 is enough for the vast majority of functions.
pub protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
}

impl VisitTags for FrameState {
Expand All @@ -85,29 +85,29 @@ impl VisitTags for FrameState {
#[derive(Debug)]
pub struct GlobalStateInner {
/// Borrow tracker method currently in use.
pub borrow_tracker_method: BorrowTrackerMethod,
borrow_tracker_method: BorrowTrackerMethod,
/// Next unused pointer ID (tag).
pub next_ptr_tag: BorTag,
next_ptr_tag: BorTag,
/// Table storing the "base" tag for each allocation.
/// The base tag is the one used for the initial pointer.
/// We need this in a separate table to handle cyclic statics.
pub base_ptr_tags: FxHashMap<AllocId, BorTag>,
base_ptr_tags: FxHashMap<AllocId, BorTag>,
/// Next unused call ID (for protectors).
pub next_call_id: CallId,
next_call_id: CallId,
/// All currently protected tags.
/// An item is protected if its tag is in this set, *and* it has the "protected" bit set.
/// We add tags to this when they are created with a protector in `reborrow`, and
/// we remove tags from this when the call which is protecting them returns, in
/// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details.
pub protected_tags: FxHashMap<BorTag, ProtectorKind>,
protected_tags: FxHashMap<BorTag, ProtectorKind>,
/// The pointer ids to trace
pub tracked_pointer_tags: FxHashSet<BorTag>,
tracked_pointer_tags: FxHashSet<BorTag>,
/// The call ids to trace
pub tracked_call_ids: FxHashSet<CallId>,
tracked_call_ids: FxHashSet<CallId>,
/// Whether to recurse into datatypes when searching for pointers to retag.
pub retag_fields: RetagFields,
retag_fields: RetagFields,
/// Whether `core::ptr::Unique` gets special (`Box`-like) handling.
pub unique_is_unique: bool,
unique_is_unique: bool,
}

impl VisitTags for GlobalStateInner {
Expand Down Expand Up @@ -194,7 +194,7 @@ impl GlobalStateInner {
}

/// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation!
pub fn new_ptr(&mut self) -> BorTag {
fn new_ptr(&mut self) -> BorTag {
let id = self.next_ptr_tag;
self.next_ptr_tag = id.succ().unwrap();
id
Expand All @@ -210,7 +210,7 @@ impl GlobalStateInner {
FrameState { call_id, protected_tags: SmallVec::new() }
}

pub fn end_call(&mut self, frame: &machine::FrameExtra<'_>) {
fn end_call(&mut self, frame: &machine::FrameExtra<'_>) {
for (_, tag) in &frame
.borrow_tracker
.as_ref()
Expand Down Expand Up @@ -355,6 +355,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed),
}
}

fn on_stack_pop(
&self,
frame: &Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
) -> InterpResult<'tcx> {
let this = self.eval_context_ref();
let borrow_tracker = this.machine.borrow_tracker.as_ref().unwrap();
// The body of this loop needs `borrow_tracker` immutably
// so we can't move this code inside the following `end_call`.
for (alloc_id, tag) in &frame
.extra
.borrow_tracker
.as_ref()
.expect("we should have borrow tracking data")
.protected_tags
{
// Just because the tag is protected doesn't guarantee that
// the allocation still exists (weak protectors allow deallocations)
// so we must check that the allocation exists.
// If it does exist, then we have the guarantee that the
// pointer is readable, and the implicit read access inserted
// will never cause UB on the pointer itself.
let (_, _, kind) = this.get_alloc_info(*alloc_id);
if matches!(kind, AllocKind::LiveData) {
let alloc_extra = this.get_alloc_extra(*alloc_id).unwrap();
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?;
}
}
borrow_tracker.borrow_mut().end_call(&frame.extra);
Ok(())
}
}

/// Extra per-allocation data for borrow tracking
Expand Down
30 changes: 2 additions & 28 deletions src/tools/miri/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1409,34 +1409,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
) -> InterpResult<'tcx> {
// We want this *before* the return value copy, because the return place itself is protected
// until we do `end_call` here.
if let Some(global_borrow_tracker) = &ecx.machine.borrow_tracker {
// The body of this loop needs `global_borrow_tracker` immutably
// so we can't move this code inside the following `end_call`.
for (alloc_id, tag) in &frame
.extra
.borrow_tracker
.as_ref()
.expect("we should have borrow tracking data")
.protected_tags
{
// Just because the tag is protected doesn't guarantee that
// the allocation still exists (weak protectors allow deallocations)
// so we must check that the allocation exists.
// If it does exist, then we have the guarantee that the
// pointer is readable, and the implicit read access inserted
// will never cause UB on the pointer itself.
let (_, _, kind) = ecx.get_alloc_info(*alloc_id);
if matches!(kind, AllocKind::LiveData) {
let alloc_extra = ecx.get_alloc_extra(*alloc_id).unwrap();
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
alloc_borrow_tracker.release_protector(
&ecx.machine,
global_borrow_tracker,
*tag,
)?;
}
}
global_borrow_tracker.borrow_mut().end_call(&frame.extra);
if ecx.machine.borrow_tracker.is_some() {
ecx.on_stack_pop(frame)?;
}
Ok(())
}
Expand Down
64 changes: 63 additions & 1 deletion src/tools/miri/src/shims/unix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ fn is_dyn_sym(name: &str, target_os: &str) -> bool {
// `signal` is set up as a weak symbol in `init_extern_statics` (on Android) so we might as
// well allow it in `dlsym`.
"signal" => true,
// needed at least on macOS to avoid file-based fallback in getrandom
"getentropy" => true,
// Give specific OSes a chance to allow their symbols.
_ =>
match target_os {
Expand Down Expand Up @@ -250,6 +252,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(result, dest)?;
}

"reallocarray" => {
// Currently this function does not exist on all Unixes, e.g. on macOS.
if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd") {
throw_unsup_format!(
"`reallocarray` is not supported on {}",
this.tcx.sess.target.os
);
}
let [ptr, nmemb, size] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let nmemb = this.read_target_usize(nmemb)?;
let size = this.read_target_usize(size)?;
// reallocarray checks a possible overflow and returns ENOMEM
// if that happens.
//
// Linux: https://www.unix.com/man-page/linux/3/reallocarray/
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
match nmemb.checked_mul(size) {
None => {
let einval = this.eval_libc("ENOMEM");
this.set_last_error(einval)?;
this.write_null(dest)?;
}
Some(len) => {
let res = this.realloc(ptr, len, MiriMemoryKind::C)?;
this.write_pointer(res, dest)?;
}
}
}

// Dynamic symbol loading
"dlsym" => {
let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
Expand Down Expand Up @@ -525,6 +558,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let result = this.getpid()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"getentropy" => {
// This function is non-standard but exists with the same signature and behavior on
// Linux, macOS, and FreeBSD.
if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd") {
throw_unsup_format!(
"`getentropy` is not supported on {}",
this.tcx.sess.target.os
);
}

let [buf, bufsize] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;

// getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
// Linux: https://man7.org/linux/man-pages/man3/getentropy.3.html
// macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
if bufsize > 256 {
let err = this.eval_libc("EIO");
this.set_last_error(err)?;
this.write_scalar(Scalar::from_i32(-1), dest)?
} else {
this.gen_random(buf, bufsize)?;
this.write_scalar(Scalar::from_i32(0), dest)?;
}
}

// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
Expand Down Expand Up @@ -594,7 +655,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_int(super::UID, dest)?;
}

"getpwuid_r" if this.frame_in_std() => {
"getpwuid_r"
if this.frame_in_std() => {
let [uid, pwd, buf, buflen, result] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.check_no_isolation("`getpwuid_r`")?;
Expand Down
15 changes: 15 additions & 0 deletions src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.read_scalar(len)?,
)?;
}
"getrandom" => {
let [ptr, len, flags] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
let _flags = this.read_scalar(flags)?.to_i32()?;
// flags on freebsd does not really matter
// in practice, GRND_RANDOM does not particularly draw from /dev/random
// since it is the same as to /dev/urandom.
// GRND_INSECURE is only an alias of GRND_NONBLOCK, which
// does not affect the RNG.
// https://man.freebsd.org/cgi/man.cgi?query=getrandom&sektion=2&n=1
this.gen_random(ptr, len)?;
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
}

// errno
"__error" => {
Expand Down
16 changes: 2 additions & 14 deletions src/tools/miri/src/shims/unix/macos/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;

pub fn is_dyn_sym(name: &str) -> bool {
matches!(name, "getentropy")
pub fn is_dyn_sym(_name: &str) -> bool {
false
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
Expand Down Expand Up @@ -113,18 +113,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(result, dest)?;
}

// Random generation related shims
"getentropy" => {
let [buf, bufsize] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;

this.gen_random(buf, bufsize)?;

this.write_scalar(Scalar::from_i32(0), dest)?; // KERN_SUCCESS
}

// Access to command-line arguments
"_NSGetArgc" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
Expand Down
4 changes: 2 additions & 2 deletions src/tools/miri/test_dependencies/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ edition = "2021"
libc = "0.2"
num_cpus = "1.10.1"

getrandom_1 = { package = "getrandom", version = "0.1" }
getrandom = { version = "0.2", features = ["js"] }
getrandom_01 = { package = "getrandom", version = "0.1" }
getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
rand = { version = "0.8", features = ["small_rng"] }

[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
Expand Down
10 changes: 5 additions & 5 deletions src/tools/miri/tests/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
program.args.push(flag);
}

// Add a test env var to do environment communication tests.
program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));
// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
program.envs.push(("MIRI_TEMP".into(), Some(env::temp_dir().into())));

let mut config = Config {
target: Some(target.to_owned()),
stderr_filters: STDERR.clone(),
Expand Down Expand Up @@ -232,11 +237,6 @@ fn main() -> Result<()> {
}
}

// Add a test env var to do environment communication tests.
env::set_var("MIRI_ENV_VAR_TEST", "0");
// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
env::set_var("MIRI_TEMP", env::temp_dir());

ui(Mode::Pass, "tests/pass", &target, WithoutDependencies)?;
ui(Mode::Pass, "tests/pass-dep", &target, WithDependencies)?;
ui(Mode::Panic, "tests/panic", &target, WithDependencies)?;
Expand Down
10 changes: 10 additions & 0 deletions src/tools/miri/tests/pass-dep/getrandom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// mac-os `getrandom_01` does some pointer shenanigans
//@compile-flags: -Zmiri-permissive-provenance

/// Test direct calls of getrandom 0.1 and 0.2.
/// Make sure they work even with isolation enabled (i.e., we do not hit a file-based fallback path).
fn main() {
let mut data = vec![0; 16];
getrandom_01::getrandom(&mut data).unwrap();
getrandom_02::getrandom(&mut data).unwrap();
}
8 changes: 0 additions & 8 deletions src/tools/miri/tests/pass-dep/getrandom_1.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//@compile-flags: -Zmiri-strict-provenance
use rand::{rngs::SmallRng, Rng, SeedableRng};
use rand::prelude::*;

// Test using the `rand` crate to generate randomness.
fn main() {
// Test `getrandom` directly.
let mut data = vec![0; 16];
getrandom::getrandom(&mut data).unwrap();
// Fully deterministic seeding.
let mut rng = SmallRng::seed_from_u64(42);
let _val = rng.gen::<i32>();
let _val = rng.gen::<isize>();
let _val = rng.gen::<i128>();

// Try seeding with "real" entropy.
let mut rng = SmallRng::from_entropy();
Expand Down
Loading