This PR adds two new Miri-defined extern functions:
`miri_get_backtrace` and `miri_resolve_frame`, which are documented in
the README. Together, they allow obtaining a backtrace for the currently
executing program.
I've added a test showing how these APIs are used. I've also prepared a
companion PR `backtrace-rs`, which will allow
`backtrace::Backtrace::new()` to work automatically under Miri.
Once these two PRs are merged, we will be able to print backtraces from
the normal Rust panic hook (since libstd is now using backtrace-rs).
A few notes:
* Resolving the backtrace frames is *very* slow - you can actually see
each line being printed out one at a time. Some local testing showed
that this is not (primrary) caused by resolving a `Span` - it seems
to be just Miri being slow.
* For the first time, we now interact directly with a user-defined
struct (instead of just executing the user-provided MIR that
manipulates the struct). To allow for future changes, I've added
a 'version' parameter (currently required to be 0). This should allow
us to change the `MiriFrame` struct should the need ever arise.
* I used the approach suggested by @oli-obk - a returned backtrace
pointer consists of a base function allocation, with the 'offset'
used to encode the `Span.lo`. This allows losslessly reconstructing
the location information in `miri_resolve_frame`.
* There are a few quirks on the `backtrace-rs` side:
* `backtrace-rs` calls `getcwd()` by default to try to simplify
the filename. This results in an isolation error by default,
which could be annoying when printing a backtrace from libstd.
* `backtrace-rs` tries to remove 'internal' frames (everything between
the call to `Backtrace::new()` and the internal API call made by
backtrace-rs) by comparing the returned frame pointer value to
a Rust function pointer. This doesn't work due to the way we
construct the frame pointers passed to the caller. We could
attempt to support this kind of comparison, or just add a
`#[cfg(miri)]` and ignore the frames ourselves.
Support F_DUPFD on stdin/stdout/stderr
Enable `close`-ing stdin/stdout/stderr
For `dup`, check if FD is `File` first
If not, clone the appropriate standard IO stream
Merge POSIX `close` and `dup` tests into same module
Also, add assertion that `write` on a closed FD returns an error.
Add `dup` as FileDescriptor trait fn
Also:
- Fix `close` so it drops `self` instead of reference to it
- Remove FD clamping in insert_fd_with_min_fd, since FDs 0-2 can be
closed
Fix fs_libc tests
Make error message when closing stdin/out/err more specific
Return io::Result from `FileDescriptor::dup`
Change error message when closing stdin/out/err
Refactor `FileDescriptor::dup` impl for `FileHandle`
Remove empty line
Nanosleep
This PR adds a shim for `libc::nanosleep`, (available under -Zmiri-disable-isolation only) which backs `thread::sleep` on Linux and macOS. I started off by extracting the `timespec` parsing from the `pthread_cond_timedwait` shim into a helper method, and adding checks for invalid values. The second commit adds the new shim and a small test. The shim blocks the current thread, and registers a timeout callback to unblock the thread again, using the same method as `pthread_cond_timedwait` does.
Move panic payload state from Machine to Thread
This PR moves the panic payload storage from the `Machine` state to per-thread state. Prior to this change, if one thread panicked while another was still unwinding, Miri would fail with `thread 'rustc' panicked at 'the panic runtime should avoid double-panics', src/shims/panic.rs:51:9`. I ran into this issue while prototyping a round-robin scheduler, but it's also reachable with the current scheduler and contrived programs that use blocking API calls to cause thread switching during unwinding. I wrote a test case along those lines for this change.
Re-organize platform-specific shims
Move platform-specific code to `shims::{posix::{linux, macos}, windows}`. Also make it private in these modules to ensure we are reasonably structured.
Add file sync shims
This PR adds shim implementations for these related file syncing functions.
* `fsync`, for POSIX targets, backed by `File::sync_all()`
* `fdatasync`, for POSIX targets, backed by `File::sync_data()`
* `fcntl` with command `F_FULLFSYNC`, for macOS targets, backed by `File::sync_all()`
* `sync_file_range`, for Linux targets, backed by `File::sync_data()`
Handle std::sync::atomic::spin_loop_hint()
This PR adds support for `std::sync::atomic::spin_loop_hint()` by implementing the `llvm.x86.sse2.pause` intrinsic when the target is x86-based. It appears this is the first LLVM intrinsic in foreign_items, so I added a couple match blocks to handle it or fall through to the different OS-specific methods. I added a basic smoke test to `tests/run-pass/sync.rs`. I came across this by way of `crossbeam::utils::Backoff::spin()`, FWIW.
implement float_to_int_unchecked
@hanna-kruppe would be great if you could have a look at this.
`float.rs` tests legal casts. `test_cast` checks that both `as` casts and unchecked casts work (i.e., these are not saturating). The `compile-fail` tests should ensure that illegal casts via the intrinsic are detected as such.
Fixes https://github.com/rust-lang/miri/issues/1264
Implement `mach_timebase_info` for macOS
Since we return nanoseceonds instead of ticks from `mach_absolute_time`, we don't need to scale the absolute time
Fixes#1288
Add shims for RwLock::try_read/RwLock::try_write
This implements proper locking so that we can check for reentrancy and implement the `try_*` methods.
Fixes https://github.com/rust-lang/miri/issues/781
Add support for 'std::time::Instant' in Windows
Add support for creating `std::time::Instant` in Windows
Includes shims for `QueryPerformanceCounter` & `QueryPerformanceFrequency` in Windows, which are both called in Windows when `std::time::Instant` is created.
Windows docs page ["Acquiring high-resolution time stamps"](https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps) was helpful in learning how `QueryPerformanceCounter` & `QueryPerformanceFrequency` work.
closes#1291
Add support for OpenOptions::create_new()/O_EXCL
This PR extends the POSIX shim for `open` to support the `O_EXCL` flag, when it is used alongside `O_CREAT`, and exercises it by testing `OpenOptions::create_new`.
Environ shim
Remake of https://github.com/rust-lang/miri/pull/1147. There are three main problems with this:
1. For some reason `update_environ` is not updating `environ` when `setenv` or `unsetenv` are called. Even then it works during initialization.
2. I am not deallocating the old array with the variables in `update_environ`.
3. I had to store the `environ` place into `MemoryExtra` as a field to update it. I was thinking about changing `extern_statics` to store places instead of `AllocID`s to avoid this.
@RalfJung
Add directory-related shims
This PR adds support for `mkdir`, `rmdir`, `opendir`, `closedir`, and `readdir64_r`.
Open directory streams are tracked through a HashMap indexed by pointer locations, which holds directory iterators. Since `DIR` is an opaque type in glibc, I represent them with 1-byte allocations, and then just use their pointers in HashMap lookups.
Tests are included to exercise the new functionality.
Add shim for rename
This adds a straightforward shim for rename, which is used by `std::fs::rename`. Testing is included.
As a heads up, I expect one or two merge conflicts between my PRs, since some of them touch the same `use` statements, or add items near the same places. I'll rebase and fix them as they come up.
Add no-op shim for posix_fadvise
This function is present in the libc crate, but not exposed through the standard library anywhere, so I haven't included a test for it.
Add statx shim for linux target
This is an attempt to fix: https://github.com/rust-lang/miri/issues/999 (for linux only)
Currently there is one problem that I haven't been able to solve. `std::fs::metadata` fails because the creation time is not available even though it is provided in the shim code.
In order to inform the caller that the field was provided, the `stx_flag` field must have the bits of `STATX_BTIME` set (which they are). The creation time is in the `stx_btime` field of the `statx` struct (see [1]). The relevant code in `libstd` is here (probably?): https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/fs.rs#L322
Another important point is that we are just providing the fields that are available in "all" platforms (this is, without using any platform specific traits or so). This can be improved later.
References:
[1] Man page: http://man7.org/linux/man-pages/man2/statx.2.html
[2] libc `statx` struct: https://docs.rs/libc/0.2.63/libc/struct.statx.html
Edit: The problem is that my filesystem is not providing it and I thought all filesystems could provide it. I changed the code so it only provides those dates if they are available. now we are ready to go.
r? @RalfJung @oli-obk