Skip to content

Commit c9613f8

Browse files
authored
Rollup merge of rust-lang#139630 - RalfJung:miri-sync, r=RalfJung
Miri subtree update r? `@ghost` a sync is needed to fix the miri-test-libstd failures
2 parents 9b9d098 + 955d92f commit c9613f8

File tree

27 files changed

+1532
-229
lines changed

27 files changed

+1532
-229
lines changed

Diff for: Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,7 @@ name = "miri"
23122312
version = "0.1.0"
23132313
dependencies = [
23142314
"aes",
2315+
"bitflags",
23152316
"chrono",
23162317
"chrono-tz",
23172318
"colored",

Diff for: src/tools/miri/Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ name = "miri"
538538
version = "0.1.0"
539539
dependencies = [
540540
"aes",
541+
"bitflags",
541542
"chrono",
542543
"chrono-tz",
543544
"colored",

Diff for: src/tools/miri/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ measureme = "12"
2626
chrono = { version = "0.4.38", default-features = false }
2727
chrono-tz = "0.10"
2828
directories = "6"
29+
bitflags = "2.6"
2930

3031
# Copied from `compiler/rustc/Cargo.toml`.
3132
# But only for some targets, it fails for others. Rustc configures this in its CI, but we can't

Diff for: src/tools/miri/ci/ci.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ case $HOST_TARGET in
164164
# Partially supported targets (tier 2)
165165
BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
166166
UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
167-
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
167+
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe concurrency sync
168168
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
169169
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync concurrency thread epoll eventfd
170170
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm

Diff for: src/tools/miri/rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
25a615bf829b9f6d6f22da537e3851043f92e5f2
1+
7d7de5bf3c3cbf9c2c5bbc5cbfb9197a8a427d35

Diff for: src/tools/miri/src/shims/files.rs

+105-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::any::Any;
22
use std::collections::BTreeMap;
3-
use std::io::{IsTerminal, SeekFrom, Write};
3+
use std::fs::{File, Metadata};
4+
use std::io::{IsTerminal, Seek, SeekFrom, Write};
45
use std::marker::CoercePointee;
56
use std::ops::Deref;
67
use std::rc::{Rc, Weak};
@@ -192,7 +193,7 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
192193
false
193194
}
194195

195-
fn as_unix(&self) -> &dyn UnixFileDescription {
196+
fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
196197
panic!("Not a unix file descriptor: {}", self.name());
197198
}
198199
}
@@ -278,6 +279,97 @@ impl FileDescription for io::Stderr {
278279
}
279280
}
280281

282+
#[derive(Debug)]
283+
pub struct FileHandle {
284+
pub(crate) file: File,
285+
pub(crate) writable: bool,
286+
}
287+
288+
impl FileDescription for FileHandle {
289+
fn name(&self) -> &'static str {
290+
"file"
291+
}
292+
293+
fn read<'tcx>(
294+
self: FileDescriptionRef<Self>,
295+
communicate_allowed: bool,
296+
ptr: Pointer,
297+
len: usize,
298+
ecx: &mut MiriInterpCx<'tcx>,
299+
finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
300+
) -> InterpResult<'tcx> {
301+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
302+
303+
let result = ecx.read_from_host(&self.file, len, ptr)?;
304+
finish.call(ecx, result)
305+
}
306+
307+
fn write<'tcx>(
308+
self: FileDescriptionRef<Self>,
309+
communicate_allowed: bool,
310+
ptr: Pointer,
311+
len: usize,
312+
ecx: &mut MiriInterpCx<'tcx>,
313+
finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
314+
) -> InterpResult<'tcx> {
315+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
316+
317+
let result = ecx.write_to_host(&self.file, len, ptr)?;
318+
finish.call(ecx, result)
319+
}
320+
321+
fn seek<'tcx>(
322+
&self,
323+
communicate_allowed: bool,
324+
offset: SeekFrom,
325+
) -> InterpResult<'tcx, io::Result<u64>> {
326+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
327+
interp_ok((&mut &self.file).seek(offset))
328+
}
329+
330+
fn close<'tcx>(
331+
self,
332+
communicate_allowed: bool,
333+
_ecx: &mut MiriInterpCx<'tcx>,
334+
) -> InterpResult<'tcx, io::Result<()>> {
335+
assert!(communicate_allowed, "isolation should have prevented even opening a file");
336+
// We sync the file if it was opened in a mode different than read-only.
337+
if self.writable {
338+
// `File::sync_all` does the checks that are done when closing a file. We do this to
339+
// to handle possible errors correctly.
340+
let result = self.file.sync_all();
341+
// Now we actually close the file and return the result.
342+
drop(self.file);
343+
interp_ok(result)
344+
} else {
345+
// We drop the file, this closes it but ignores any errors
346+
// produced when closing it. This is done because
347+
// `File::sync_all` cannot be done over files like
348+
// `/dev/urandom` which are read-only. Check
349+
// https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
350+
// for a deeper discussion.
351+
drop(self.file);
352+
interp_ok(Ok(()))
353+
}
354+
}
355+
356+
fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
357+
interp_ok(self.file.metadata())
358+
}
359+
360+
fn is_tty(&self, communicate_allowed: bool) -> bool {
361+
communicate_allowed && self.file.is_terminal()
362+
}
363+
364+
fn as_unix<'tcx>(&self, ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
365+
assert!(
366+
ecx.target_os_is_unix(),
367+
"unix file operations are only available for unix targets"
368+
);
369+
self
370+
}
371+
}
372+
281373
/// Like /dev/null
282374
#[derive(Debug)]
283375
pub struct NullOutput;
@@ -300,10 +392,13 @@ impl FileDescription for NullOutput {
300392
}
301393
}
302394

395+
/// Internal type of a file-descriptor - this is what [`FdTable`] expects
396+
pub type FdNum = i32;
397+
303398
/// The file descriptor table
304399
#[derive(Debug)]
305400
pub struct FdTable {
306-
pub fds: BTreeMap<i32, DynFileDescriptionRef>,
401+
pub fds: BTreeMap<FdNum, DynFileDescriptionRef>,
307402
/// Unique identifier for file description, used to differentiate between various file description.
308403
next_file_description_id: FdId,
309404
}
@@ -339,21 +434,21 @@ impl FdTable {
339434
}
340435

341436
/// Insert a new file description to the FdTable.
342-
pub fn insert_new(&mut self, fd: impl FileDescription) -> i32 {
437+
pub fn insert_new(&mut self, fd: impl FileDescription) -> FdNum {
343438
let fd_ref = self.new_ref(fd);
344439
self.insert(fd_ref)
345440
}
346441

347-
pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> i32 {
442+
pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> FdNum {
348443
self.insert_with_min_num(fd_ref, 0)
349444
}
350445

351446
/// Insert a file description, giving it a file descriptor that is at least `min_fd_num`.
352447
pub fn insert_with_min_num(
353448
&mut self,
354449
file_handle: DynFileDescriptionRef,
355-
min_fd_num: i32,
356-
) -> i32 {
450+
min_fd_num: FdNum,
451+
) -> FdNum {
357452
// Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
358453
// between used FDs, the find_map combinator will return it. If the first such unused FD
359454
// is after all other used FDs, the find_map combinator will return None, and we will use
@@ -379,16 +474,16 @@ impl FdTable {
379474
new_fd_num
380475
}
381476

382-
pub fn get(&self, fd_num: i32) -> Option<DynFileDescriptionRef> {
477+
pub fn get(&self, fd_num: FdNum) -> Option<DynFileDescriptionRef> {
383478
let fd = self.fds.get(&fd_num)?;
384479
Some(fd.clone())
385480
}
386481

387-
pub fn remove(&mut self, fd_num: i32) -> Option<DynFileDescriptionRef> {
482+
pub fn remove(&mut self, fd_num: FdNum) -> Option<DynFileDescriptionRef> {
388483
self.fds.remove(&fd_num)
389484
}
390485

391-
pub fn is_fd_num(&self, fd_num: i32) -> bool {
486+
pub fn is_fd_num(&self, fd_num: FdNum) -> bool {
392487
self.fds.contains_key(&fd_num)
393488
}
394489
}

Diff for: src/tools/miri/src/shims/time.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -219,16 +219,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
219219

220220
let filetime = this.deref_pointer_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?;
221221

222-
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
223-
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
224-
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH");
225-
let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
226-
let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;
227-
228-
let duration = system_time_to_duration(&SystemTime::now())?
229-
+ Duration::from_secs(SECONDS_TO_UNIX_EPOCH);
230-
let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
231-
.map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?;
222+
let duration = this.system_time_since_windows_epoch(&SystemTime::now())?;
223+
let duration_ticks = this.windows_ticks_for(duration)?;
232224

233225
let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
234226
let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
@@ -281,6 +273,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
281273
interp_ok(Scalar::from_i32(-1)) // Return non-zero on success
282274
}
283275

276+
#[allow(non_snake_case, clippy::arithmetic_side_effects)]
277+
fn system_time_since_windows_epoch(&self, time: &SystemTime) -> InterpResult<'tcx, Duration> {
278+
let this = self.eval_context_ref();
279+
280+
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
281+
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH");
282+
let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;
283+
284+
interp_ok(system_time_to_duration(time)? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
285+
}
286+
287+
#[allow(non_snake_case, clippy::arithmetic_side_effects)]
288+
fn windows_ticks_for(&self, duration: Duration) -> InterpResult<'tcx, u64> {
289+
let this = self.eval_context_ref();
290+
291+
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
292+
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
293+
let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
294+
295+
let ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
296+
.map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?;
297+
interp_ok(ticks)
298+
}
299+
284300
fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> {
285301
let this = self.eval_context_ref();
286302

Diff for: src/tools/miri/src/shims/unix/fd.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
121121
throw_unsup_format!("unsupported flags {:#x}", op);
122122
};
123123

124-
let result = fd.as_unix().flock(this.machine.communicate(), parsed_op)?;
124+
let result = fd.as_unix(this).flock(this.machine.communicate(), parsed_op)?;
125125
// return `0` if flock is successful
126126
let result = result.map(|()| 0i32);
127127
interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
@@ -273,7 +273,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
273273
let Ok(offset) = u64::try_from(offset) else {
274274
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
275275
};
276-
fd.as_unix().pread(communicate, offset, buf, count, this, finish)?
276+
fd.as_unix(this).pread(communicate, offset, buf, count, this, finish)?
277277
}
278278
};
279279
interp_ok(())
@@ -333,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
333333
let Ok(offset) = u64::try_from(offset) else {
334334
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
335335
};
336-
fd.as_unix().pwrite(communicate, buf, count, offset, this, finish)?
336+
fd.as_unix(this).pwrite(communicate, buf, count, offset, this, finish)?
337337
}
338338
};
339339
interp_ok(())

Diff for: src/tools/miri/src/shims/unix/freebsd/foreign_items.rs

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc_middle::ty::Ty;
22
use rustc_span::Symbol;
33
use rustc_target::callconv::{Conv, FnAbi};
44

5+
use super::sync::EvalContextExt as _;
56
use crate::shims::unix::*;
67
use crate::*;
78

@@ -55,6 +56,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
5556
this.write_scalar(res, dest)?;
5657
}
5758

59+
// Synchronization primitives
60+
"_umtx_op" => {
61+
let [obj, op, val, uaddr, uaddr2] =
62+
this.check_shim(abi, Conv::C, link_name, args)?;
63+
this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?;
64+
}
65+
5866
// File related shims
5967
// For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
6068
// since freebsd 12 the former form can be expected.

Diff for: src/tools/miri/src/shims/unix/freebsd/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod foreign_items;
2+
pub mod sync;

0 commit comments

Comments
 (0)