* Store the local crates in an Rc<[CrateNum]>
* Move all the allocation history into Stacks
* Clean up the implementation of get_logs_relevant_to a bit
Use atomic RMW for `{mutex, rwlock, cond, srwlock}_get_or_create_id` functions
This is required for #1963
`{mutex, rwlock, cond, srwlock}_get_or_create_id()` currently checks whether an ID field is 0 using an atomic read, allocate one and get a new ID if it is, then write it in a separate atomic write. This is fine without weak memory. For instance, in `pthread_mutex_lock` which may be called by two threads concurrently, only one thread can read 0, create and then write a new ID, the later-run thread will always see the newly created ID and never 0.
```rust
fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let kind = mutex_get_kind(this, mutex_op)?.check_init()?;
let id = mutex_get_or_create_id(this, mutex_op)?;
let active_thread = this.get_active_thread();
```
However, with weak memory behaviour, both threads may read 0: the first thread has to see 0 because nothing else was written to it, and the second thread is not guaranteed to observe the latest value, causing a duplicate mutex to be created and both threads "successfully" acquiring the lock at the same time.
This is a pretty typical pattern requiring the use of atomic RMWs. RMW *always* reads the latest value in a location, so only one thread can create the new mutex and ID, all others scheduled later will see the new ID.
* Pass a ThreadInfo down to grant/access to get the current span lazily
* Rename add_* to log_* for clarity
* Hoist borrow_mut calls out of loops by tweaking the for_each signature
* Explain the parameters of check_protector a bit more
Add a command line flag to avoid printing to stdout and stderr
This is practical for tests that don't actually care about the output and thus don't want it intermingled with miri's warnings, errors or ICEs
fixes#2083
Replace unneeded use of `ref` in favor of "match ergonomics"
The signature of `check_shim` is very amenable to this.
```rust
fn check_shim<'a, const N: usize>(…) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]>
```
Instead of:
```rust
let &[ref ptr, ref flags] = this.check_shim(…)?;
```
we can write it just as:
```rust
let [ptr, flags] = this.check_shim(…)?;
```
Clean up all trailing whitespace
Editors commonly strip trailing whitespace from source code on save, because it's almost always undesired, and that leads to spurious diffs in these files when working with them in such an editor.
Resolve some clippy lints, ignore the rest
`cargo clippy` finishes cleanly after this. I stuck to only what I think are the least objectionable lints: cleaning up useless identity conversions that do `from`/`try_from`/`into` going from T->T, extraneous `&` on expressions that are already a reference, unused lifetime parameters, and similar.
Below in the \<details\> is the complete remaining output of `cargo clippy` with the `allow` attribute removed. I think all the lints left are fine to keep ignoring.
<details>
<summary><code>$ cargo clippy -- -Dclippy::all</code></summary>
```console
error: this `else { if .. }` block can be collapsed
--> src/data_race.rs:559:16
|
559 | } else {
| ________________^
560 | | if lt { &rhs } else { &old }
561 | | };
| |_________^ help: collapse nested if block: `if lt { &rhs } else { &old }`
|
= note: `-D clippy::collapsible-else-if` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
error: this `if` statement can be collapsed
--> src/range_map.rs:166:17
|
166 | / if successful_merge_count > 0 {
167 | | if done || self.v[end_idx].data != self.v[equal_since_idx].data {
168 | | // Everything in `equal_since..end` was equal. Make them just one element covering
169 | | // the entire range.
... |
187 | | }
188 | | }
| |_________________^
|
= note: `-D clippy::collapsible-if` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
help: collapse nested if block
|
166 ~ if successful_merge_count > 0 && (done || self.v[end_idx].data != self.v[equal_since_idx].data) {
167 + // Everything in `equal_since..end` was equal. Make them just one element covering
168 + // the entire range.
169 + let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove
170 + if removed_elems > 0 {
171 + // Adjust the range of the first element to cover all of them.
...
error: this `else { if .. }` block can be collapsed
--> src/shims/foreign_items.rs:114:16
|
114 | } else {
| ________________^
115 | | if new_size == 0 {
116 | | this.deallocate_ptr(old_ptr, None, kind.into())?;
117 | | Ok(Pointer::null())
... |
127 | | }
128 | | }
| |_________^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
help: collapse nested if block
|
114 ~ } else if new_size == 0 {
115 + this.deallocate_ptr(old_ptr, None, kind.into())?;
116 + Ok(Pointer::null())
117 + } else {
118 + let new_ptr = this.reallocate_ptr(
119 + old_ptr,
...
error: this `else { if .. }` block can be collapsed
--> src/shims/posix/sync.rs:459:20
|
459 | } else {
| ____________________^
460 | | if is_mutex_kind_default(this, kind)?
461 | | || is_mutex_kind_normal(this, kind)?
462 | | || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")?
... |
472 | | }
473 | | }
| |_____________^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
help: collapse nested if block
|
459 ~ } else if is_mutex_kind_default(this, kind)?
460 + || is_mutex_kind_normal(this, kind)?
461 + || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")?
462 + {
463 + this.eval_libc_i32("EBUSY")
464 + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
...
error: this `if` statement can be collapsed
--> src/thread.rs:132:9
|
132 | / if self.state == ThreadState::Enabled {
133 | | if self.stack.is_empty() {
134 | | self.state = ThreadState::Terminated;
135 | | return true;
136 | | }
137 | | }
| |_________^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
help: collapse nested if block
|
132 ~ if self.state == ThreadState::Enabled && self.stack.is_empty() {
133 + self.state = ThreadState::Terminated;
134 + return true;
135 + }
|
error: this `if` statement can be collapsed
--> src/thread.rs:523:13
|
523 | / if thread.state == ThreadState::Enabled {
524 | | if !self.yield_active_thread || id != self.active_thread {
525 | | self.active_thread = id;
526 | | if let Some(data_race) = data_race {
... |
530 | | }
531 | | }
| |_____________^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
help: collapse nested if block
|
523 ~ if thread.state == ThreadState::Enabled && (!self.yield_active_thread || id != self.active_thread) {
524 + self.active_thread = id;
525 + if let Some(data_race) = data_race {
526 + data_race.thread_set_active(self.active_thread);
527 + }
528 + break;
...
error: you should consider adding a `Default` implementation for `GlobalState`
--> src/data_race.rs:1132:5
|
1132 | / pub fn new() -> Self {
1133 | | let mut global_state = GlobalState {
1134 | | multi_threaded: Cell::new(false),
1135 | | vector_clocks: RefCell::new(IndexVec::new()),
... |
1155 | | global_state
1156 | | }
| |_____^
|
= note: `-D clippy::new-without-default` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
help: try adding this
|
1129 + impl Default for GlobalState {
1130 + fn default() -> Self {
1131 + Self::new()
1132 + }
1133 + }
|
error: useless use of `format!`
--> src/diagnostics.rs:155:32
|
155 | (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"pass the flag `-Zmiri-disable-isolation` to disable isolation;".to_string()`
|
= note: `-D clippy::useless-format` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: useless use of `format!`
--> src/diagnostics.rs:156:32
|
156 | ...e, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning"...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: useless use of `format!`
--> src/diagnostics.rs:161:32
|
161 | ...e, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: useless use of `format!`
--> src/diagnostics.rs:197:33
|
197 | ...e, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: useless use of `format!`
--> src/diagnostics.rs:202:32
|
202 | ... (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"this usually indicates that your program performed an invalid operation and caused Undefined Behavior".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: useless use of `format!`
--> src/diagnostics.rs:203:32
|
203 | (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: useless use of `format!`
--> src/diagnostics.rs:207:32
|
207 | ... (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: useless use of `format!`
--> src/diagnostics.rs:208:32
|
208 | ...(None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
--> src/diagnostics.rs:247:5
|
247 | / match e.kind() {
248 | | UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
249 | | eprintln!(
250 | | "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
... |
256 | | _ => {}
257 | | }
| |_____^
|
= note: `-D clippy::single-match` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match
help: try this
|
247 ~ if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) = e.kind() {
248 + eprintln!(
249 + "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
250 + access.uninit_offset.bytes(),
251 + access.uninit_offset.bytes() + access.uninit_size.bytes(),
252 + );
...
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
--> src/machine.rs:92:1
|
92 | impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::from-over-into` implied by `-D clippy::all`
= help: consider to implement `From<machine::MiriMemoryKind>` instead
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
error: manual implementation of `Option::map`
--> src/machine.rs:570:22
|
570 | let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
| ______________________^
571 | | Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind))
572 | | } else {
573 | | None
574 | | };
| |_________^ help: try this: `ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind))`
|
= note: `-D clippy::manual-map` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
error: manual implementation of `Option::map`
--> src/machine.rs:575:26
|
575 | let race_alloc = if let Some(data_race) = &ecx.machine.data_race {
| __________________________^
576 | | Some(data_race::AllocExtra::new_allocation(data_race, alloc.size(), kind))
577 | | } else {
578 | | None
579 | | };
| |_________^ help: try this: `ecx.machine.data_race.as_ref().map(|data_race| data_race::AllocExtra::new_allocation(data_race, alloc.size(), kind))`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
error: variant name ends with the enum's name
--> src/shims/intrinsics.rs:354:21
|
354 | MirOp(mir::UnOp),
| ^^^^^^^^^^^^^^^^
|
= note: `-D clippy::enum-variant-names` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
error: variant name ends with the enum's name
--> src/shims/intrinsics.rs:453:21
|
453 | MirOp(BinOp),
| ^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
error: variant name ends with the enum's name
--> src/shims/intrinsics.rs:454:21
|
454 | SaturatingOp(BinOp),
| ^^^^^^^^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
error: variant name ends with the enum's name
--> src/shims/intrinsics.rs:580:21
|
580 | MirOp(BinOp),
| ^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
--> src/shims/intrinsics.rs:1391:1
|
1391 | fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::needless-lifetimes` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
error: this `if` has identical blocks
--> src/shims/posix/sync.rs:503:75
|
503 | } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
| ___________________________________________________________________________^
504 | | this.eval_libc_i32("EPERM")
505 | | } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
| |_____________^
|
= note: `-D clippy::if-same-then-else` implied by `-D clippy::all`
note: same as this
--> src/shims/posix/sync.rs:505:74
|
505 | } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
| __________________________________________________________________________^
506 | | this.eval_libc_i32("EPERM")
507 | | } else {
| |_____________^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
error: this `if` has identical blocks
--> src/shims/posix/sync.rs:610:57
|
610 | if this.rwlock_reader_unlock(id, active_thread) {
| _________________________________________________________^
611 | | Ok(0)
612 | | } else if this.rwlock_writer_unlock(id, active_thread) {
| |_________^
|
note: same as this
--> src/shims/posix/sync.rs:612:64
|
612 | } else if this.rwlock_writer_unlock(id, active_thread) {
| ________________________________________________________________^
613 | | Ok(0)
614 | | } else {
| |_________^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
error: useless use of `format!`
--> src/stacked_borrows.rs:228:14
|
228 | url: format!(
| ______________^
229 | | "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"
230 | | ),
| |_________^ help: consider using `.to_string()`: `"https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md".to_string()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
error: field assignment outside of initializer for an instance created with Default::default()
--> src/thread.rs:234:9
|
234 | main_thread.join_status = ThreadJoinStatus::Detached;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::field-reassign-with-default` implied by `-D clippy::all`
note: consider initializing the variable with `Thread::<'_, '_> { join_status: ThreadJoinStatus::Detached, ..Default::default() }` and removing relevant reassignments
--> src/thread.rs:232:9
|
232 | let mut main_thread = Thread::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
error: `if` chain can be rewritten with `match`
--> src/vector_clock.rs:224:17
|
224 | / if l > r {
225 | | return false;
226 | | } else if l < r {
227 | | equal = false;
228 | | }
| |_________________^
|
= note: `-D clippy::comparison-chain` implied by `-D clippy::all`
= help: consider rewriting the `if` chain to use `cmp` and `match`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
error: `if` chain can be rewritten with `match`
--> src/vector_clock.rs:278:17
|
278 | / if l < r {
279 | | return false;
280 | | } else if l > r {
281 | | equal = false;
282 | | }
| |_________________^
|
= help: consider rewriting the `if` chain to use `cmp` and `match`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
error: manual `RangeInclusive::contains` implementation
--> src/bin/miri.rs:473:37
|
473 | Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(0.0..=1.0).contains(&rate)`
|
= note: `-D clippy::manual-range-contains` implied by `-D clippy::all`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
```
</details>