Skip to content

Commit aaaed51

Browse files
committed
Auto merge of rust-lang#2279 - RalfJung:adjacent-allocs, r=RalfJung
Allow non-ZST allocations to be adjacent Also `cargo update` in test-cargo-miri... no need to make a separate PR for that right?...
2 parents aefaa5b + 6549764 commit aaaed51

File tree

6 files changed

+106
-51
lines changed

6 files changed

+106
-51
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ environment variable. We first document the most relevant and most commonly used
277277
and `warn-nobacktrace` are the supported actions. The default is to `abort`,
278278
which halts the machine. Some (but not all) operations also support continuing
279279
execution with a "permission denied" error being returned to the program.
280-
`warn` prints a full backtrace when that happen; `warn-nobacktrace` is less
280+
`warn` prints a full backtrace when that happens; `warn-nobacktrace` is less
281281
verbose. `hide` hides the warning entirely.
282282
* `-Zmiri-env-exclude=<var>` keeps the `var` environment variable isolated from the host so that it
283283
cannot be accessed by the program. Can be used multiple times to exclude several variables. The

src/intptrcast.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::cell::RefCell;
2+
use std::cmp::max;
23
use std::collections::hash_map::Entry;
34

45
use log::trace;
@@ -187,11 +188,11 @@ impl<'mir, 'tcx> GlobalStateInner {
187188
slack,
188189
);
189190

190-
// Remember next base address. Leave a gap of at least 1 to avoid two zero-sized allocations
191-
// having the same base address, and to avoid ambiguous provenance for the address between two
192-
// allocations (also see https://github.com/rust-lang/unsafe-code-guidelines/issues/313).
193-
let size_plus_1 = size.bytes().checked_add(1).unwrap();
194-
global_state.next_base_addr = base_addr.checked_add(size_plus_1).unwrap();
191+
// Remember next base address. If this allocation is zero-sized, leave a gap
192+
// of at least 1 to avoid two allocations having the same base address.
193+
// (The logic in `alloc_id_from_addr` assumes unique addresses, and function
194+
// pointers to different functions need to be distinguishable!)
195+
global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap();
195196
// Given that `next_base_addr` increases in each allocation, pushing the
196197
// corresponding tuple keeps `int_to_ptr_map` sorted
197198
global_state.int_to_ptr_map.push((base_addr, alloc_id));

test-cargo-miri/Cargo.lock

+34-44
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test-cargo-miri/run-test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def test_cargo_miri_test():
114114
default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref"
115115
filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref"
116116

117-
# macOS needs permissive provenance inside getrandom.
117+
# macOS needs permissive provenance inside getrandom_1.
118118
test("`cargo miri test`",
119119
cargo_miri("test"),
120120
default_ref, "test.stderr-empty.ref",

tests/pass/adjacent-allocs.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
// compile-flags: -Zmiri-permissive-provenance
22

3+
fn ensure_allocs_can_be_adjacent() {
4+
for _ in 0..512 {
5+
let n = 0u64;
6+
let ptr: *const u64 = &n;
7+
let ptr2 = {
8+
let m = 0u64;
9+
&m as *const u64
10+
};
11+
if ptr.wrapping_add(1) == ptr2 {
12+
return;
13+
}
14+
}
15+
panic!("never saw adjacent stack variables?");
16+
}
17+
318
fn test1() {
419
// The slack between allocations is random.
520
// Loop a few times to hit the zero-slack case.
@@ -42,6 +57,7 @@ fn test2() {
4257
}
4358

4459
fn main() {
60+
ensure_allocs_can_be_adjacent();
4561
test1();
4662
test2();
4763
}

tests/pass/intptrcast.rs

+48
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// compile-flags: -Zmiri-permissive-provenance
22

3+
use std::mem;
4+
35
// This strips provenance
46
fn transmute_ptr_to_int<T>(x: *const T) -> usize {
57
unsafe { std::mem::transmute(x) }
@@ -100,6 +102,51 @@ fn zst_deref_of_dangling() {
100102
let _val = unsafe { *zst };
101103
}
102104

105+
fn functions() {
106+
// Roundtrip a few functions through integers. Do this multiple times to make sure this does not
107+
// work by chance. If we did not give unique addresses to ZST allocations -- which fn
108+
// allocations are -- then we might be unable to cast back, or we might call the wrong function!
109+
// Every function gets at most one address so doing a loop would not help...
110+
fn fn0() -> i32 {
111+
0
112+
}
113+
fn fn1() -> i32 {
114+
1
115+
}
116+
fn fn2() -> i32 {
117+
2
118+
}
119+
fn fn3() -> i32 {
120+
3
121+
}
122+
fn fn4() -> i32 {
123+
4
124+
}
125+
fn fn5() -> i32 {
126+
5
127+
}
128+
fn fn6() -> i32 {
129+
6
130+
}
131+
fn fn7() -> i32 {
132+
7
133+
}
134+
let fns = [
135+
fn0 as fn() -> i32 as *const () as usize,
136+
fn1 as fn() -> i32 as *const () as usize,
137+
fn2 as fn() -> i32 as *const () as usize,
138+
fn3 as fn() -> i32 as *const () as usize,
139+
fn4 as fn() -> i32 as *const () as usize,
140+
fn5 as fn() -> i32 as *const () as usize,
141+
fn6 as fn() -> i32 as *const () as usize,
142+
fn7 as fn() -> i32 as *const () as usize,
143+
];
144+
for (idx, &addr) in fns.iter().enumerate() {
145+
let fun: fn() -> i32 = unsafe { mem::transmute(addr as *const ()) };
146+
assert_eq!(fun(), idx as i32);
147+
}
148+
}
149+
103150
fn main() {
104151
cast();
105152
cast_dangling();
@@ -112,4 +159,5 @@ fn main() {
112159
ptr_eq_out_of_bounds_null();
113160
ptr_eq_integer();
114161
zst_deref_of_dangling();
162+
functions();
115163
}

0 commit comments

Comments
 (0)