Implement a garbage collector for tags
The general approach here is to scan TLS, all locals, and the main memory map for all provenance, accumulating a `HashSet` of all pointer tags which are stored anywhere (we also have a special case for panic payloads). Then we iterate over every borrow stack and remove tags which are not in said `HashSet`, or which could be terminating a SRW block.
Runtime of benchmarks decreases by between 17% and 81%.
GC off:
```
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/backtraces/Cargo.toml
Time (mean ± σ): 7.080 s ± 0.249 s [User: 6.870 s, System: 0.202 s]
Range (min … max): 6.933 s … 7.521 s 5 runs
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet PC without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/mse/Cargo.toml
Time (mean ± σ): 1.875 s ± 0.031 s [User: 1.630 s, System: 0.245 s]
Range (min … max): 1.825 s … 1.910 s 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/serde1/Cargo.toml
Time (mean ± σ): 2.785 s ± 0.075 s [User: 2.536 s, System: 0.168 s]
Range (min … max): 2.698 s … 2.851 s 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/serde2/Cargo.toml
Time (mean ± σ): 6.267 s ± 0.066 s [User: 6.072 s, System: 0.190 s]
Range (min … max): 6.152 s … 6.314 s 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/slice-get-unchecked/Cargo.toml
Time (mean ± σ): 4.733 s ± 0.080 s [User: 4.177 s, System: 0.513 s]
Range (min … max): 4.681 s … 4.874 s 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/unicode/Cargo.toml
Time (mean ± σ): 3.770 s ± 0.034 s [User: 3.549 s, System: 0.211 s]
Range (min … max): 3.724 s … 3.819 s 5 runs
```
GC on:
```
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/backtraces/Cargo.toml
Time (mean ± σ): 5.886 s ± 0.054 s [User: 5.696 s, System: 0.182 s]
Range (min … max): 5.799 s … 5.937 s 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/mse/Cargo.toml
Time (mean ± σ): 936.4 ms ± 7.0 ms [User: 815.4 ms, System: 119.6 ms]
Range (min … max): 925.7 ms … 945.0 ms 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/serde1/Cargo.toml
Time (mean ± σ): 2.126 s ± 0.022 s [User: 1.979 s, System: 0.146 s]
Range (min … max): 2.089 s … 2.143 s 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/serde2/Cargo.toml
Time (mean ± σ): 4.242 s ± 0.066 s [User: 4.051 s, System: 0.160 s]
Range (min … max): 4.196 s … 4.357 s 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/slice-get-unchecked/Cargo.toml
Time (mean ± σ): 907.4 ms ± 2.4 ms [User: 788.6 ms, System: 118.2 ms]
Range (min … max): 903.5 ms … 909.4 ms 5 runs
Benchmark 1: cargo +miri miri run --manifest-path /home/ben/miri/bench-cargo-miri/unicode/Cargo.toml
Time (mean ± σ): 1.821 s ± 0.011 s [User: 1.687 s, System: 0.133 s]
Range (min … max): 1.802 s … 1.831 s 5 runs
```
But much more importantly for me this drops the peak memory usage of the first 1 minute of running `regex`'s tests from 103 GB to 1.7 GB.
Thanks to `@oli-obk` for suggesting a while ago that this was possible and `@darksonn` for reminding me that we can just search through memory to find Provenance to locate pointers.
Fixes https://github.com/rust-lang/miri/issues/1367
Add a protector test that demonstrates the base tag diagnostic
Per https://github.com/rust-lang/miri/pull/2519#issuecomment-1232736295, this demonstrates this case for protector diagnostics:
```
help: <3131> was created here, as a base tag for alloc1623
--> tests/fail/stacked_borrows/invalidate_against_protector3.rs:10:19
|
10 | let ptr = std::alloc::alloc(std::alloc::Layout::for_value(&0i32)) as *mut i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
This diagnostic is inspired by what Miri used to do with https://github.com/rust-lang/rust/issues/60076#issuecomment-1214169179
Use the better FnEntry spans in protector errors
Example error, from `tests/fail/stacked_borrows/invalidate_against_protector1.rs`:
```
error: Undefined Behavior: not granting access to tag <3095> because that would remove [Unique for <3099>] which is protected because it is an argument of call 943
--> tests/fail/stacked_borrows/invalidate_against_protector1.rs:5:25
|
5 | let _val = unsafe { *x }; //~ ERROR: protect
| ^^ not granting access to tag <3095> because that would remove [Unique for <3099>] which is protected because it is an argument of call 943
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <3095> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> tests/fail/stacked_borrows/invalidate_against_protector1.rs:10:16
|
10 | let xraw = &mut x as *mut _;
| ^^^^^^
help: <3099> is this argument
--> tests/fail/stacked_borrows/invalidate_against_protector1.rs:1:23
|
1 | fn inner(x: *mut i32, _y: &mut i32) {
| ^^
= note: backtrace:
= note: inside `inner` at tests/fail/stacked_borrows/invalidate_against_protector1.rs:5:25
note: inside `main` at tests/fail/stacked_borrows/invalidate_against_protector1.rs:12:5
--> tests/fail/stacked_borrows/invalidate_against_protector1.rs:12:5
|
12 | inner(xraw, xref);
| ^^^^^^^^^^^^^^^^^
```
Benchmarks report no change, within noise.
Skip field retagging on ZSTs, it can take forever
I just tried running the `alloc`'s tests with `miri-test-libstd` with field retagging enabled. The test suite eventually hangs on a few tests which pass around ZSTs that have a lot of fields.
I don't really know how to test this effectively. The test passes, but if you remove this fast-path it effectively just hangs the interpreter. And since it hangs _inside_ a step, there's no hope for doing some kind of timeout within the test.
slightly improve protector-related error messages
I find the current retag messages confusing, since they sound like the item *was* protected, when it still actively *is* protected (and that is, in fact, the issue).
Example error message:
```
error: Undefined Behavior: not granting access to tag <3095> because incompatible item [Unique for <3099>] is protected by call 943
--> tests/fail/stacked_borrows/invalidate_against_barrier1.rs:5:25
|
5 | let _val = unsafe { *x }; //~ ERROR: protect
| ^^ not granting access to tag <3095> because incompatible item [Unique for <3099>] is protected by call 943
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <3095> was created by a SharedReadWrite retag at offsets [0x0..0x4]
--> tests/fail/stacked_borrows/invalidate_against_barrier1.rs:10:16
|
10 | let xraw = &mut x as *mut _;
| ^^^^^^
help: <3095> cannot be used for memory access because that would remove protected tag <3099>, protected by this function call
--> tests/fail/stacked_borrows/invalidate_against_barrier1.rs:1:1
|
1 | / fn inner(x: *mut i32, _y: &mut i32) {
2 | | // If `x` and `y` alias, retagging is fine with this... but we really
3 | | // shouldn't be allowed to use `x` at all because `y` was assumed to be
4 | | // unique for the duration of this call.
5 | | let _val = unsafe { *x }; //~ ERROR: protect
6 | | }
| |_^
help: <3099> was derived from <3098>, which in turn was created here
--> tests/fail/stacked_borrows/invalidate_against_barrier1.rs:12:17
|
12 | inner(xraw, xref);
| ^^^^
= note: backtrace:
= note: inside `inner` at tests/fail/stacked_borrows/invalidate_against_barrier1.rs:5:25
note: inside `main` at tests/fail/stacked_borrows/invalidate_against_barrier1.rs:12:5
--> tests/fail/stacked_borrows/invalidate_against_barrier1.rs:12:5
|
12 | inner(xraw, xref);
| ^^^^^^^^^^^^^^^^^
```
r? `@saethlin`