Skip to content

Commit 83f7657

Browse files
committed
Auto merge of #1603 - RalfJung:track-raw, r=oli-obk
add an option to track raw pointer tags in Stacked Borrows Also make error messages more informative by printing the affected memory location
2 parents 6064367 + bf54607 commit 83f7657

File tree

9 files changed

+106
-82
lines changed

9 files changed

+106
-82
lines changed

README.md

+10-3
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,20 @@ environment variable:
230230
* `-Zmiri-track-alloc-id=<id>` shows a backtrace when the given allocation is
231231
being allocated or freed. This helps in debugging memory leaks and
232232
use after free bugs.
233+
* `-Zmiri-track-call-id=<id>` shows a backtrace when the given call id is
234+
assigned to a stack frame. This helps in debugging UB related to Stacked
235+
Borrows "protectors".
233236
* `-Zmiri-track-pointer-tag=<tag>` shows a backtrace when the given pointer tag
234237
is popped from a borrow stack (which is where the tag becomes invalid and any
235238
future use of it will error). This helps you in finding out why UB is
236239
happening and where in your code would be a good place to look for it.
237-
* `-Zmiri-track-call-id=<id>` shows a backtrace when the given call id is
238-
assigned to a stack frame. This helps in debugging UB related to Stacked
239-
Borrows "protectors".
240+
* `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for
241+
raw pointers. This can make valid code fail to pass the checks, but also can
242+
help identify latent aliasing issues in code that Miri accepts by default. You
243+
can recognize false positives by "<untagged>" occurring in the message -- this
244+
indicates a pointer that was cast from an integer, so Miri was unable to track
245+
this pointer. Make sure to use a non-Windows target with this flag, as the
246+
Windows runtime makes use of integer-pointer casts.
240247

241248
Some native rustc `-Z` flags are also very relevant for Miri:
242249

src/bin/miri.rs

+3
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ fn main() {
207207
"-Zmiri-ignore-leaks" => {
208208
miri_config.ignore_leaks = true;
209209
}
210+
"-Zmiri-track-raw-pointers" => {
211+
miri_config.track_raw = true;
212+
}
210213
"--" => {
211214
after_dashdash = true;
212215
}

src/eval.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
use std::convert::TryFrom;
44
use std::ffi::OsStr;
55

6-
use rand::rngs::StdRng;
7-
use rand::SeedableRng;
86
use log::info;
97

108
use rustc_hir::def_id::DefId;
@@ -48,6 +46,8 @@ pub struct MiriConfig {
4846
pub tracked_call_id: Option<CallId>,
4947
/// The allocation id to report about.
5048
pub tracked_alloc_id: Option<AllocId>,
49+
/// Whether to track raw pointers in stacked borrows.
50+
pub track_raw: bool,
5151
}
5252

5353
impl Default for MiriConfig {
@@ -64,6 +64,7 @@ impl Default for MiriConfig {
6464
tracked_pointer_tag: None,
6565
tracked_call_id: None,
6666
tracked_alloc_id: None,
67+
track_raw: false,
6768
}
6869
}
6970
}
@@ -84,14 +85,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
8485
rustc_span::source_map::DUMMY_SP,
8586
param_env,
8687
Evaluator::new(config.communicate, config.validate, layout_cx),
87-
MemoryExtra::new(
88-
StdRng::seed_from_u64(config.seed.unwrap_or(0)),
89-
config.stacked_borrows,
90-
config.tracked_pointer_tag,
91-
config.tracked_call_id,
92-
config.tracked_alloc_id,
93-
config.check_alignment,
94-
),
88+
MemoryExtra::new(&config),
9589
);
9690
// Complete initialization.
9791
EnvVars::init(&mut ecx, config.excluded_env_vars)?;

src/machine.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::fmt;
1010

1111
use log::trace;
1212
use rand::rngs::StdRng;
13+
use rand::SeedableRng;
1314

1415
use rustc_data_structures::fx::FxHashMap;
1516
use rustc_middle::{
@@ -132,16 +133,14 @@ pub struct MemoryExtra {
132133
}
133134

134135
impl MemoryExtra {
135-
pub fn new(
136-
rng: StdRng,
137-
stacked_borrows: bool,
138-
tracked_pointer_tag: Option<PtrId>,
139-
tracked_call_id: Option<CallId>,
140-
tracked_alloc_id: Option<AllocId>,
141-
check_alignment: AlignmentCheck,
142-
) -> Self {
143-
let stacked_borrows = if stacked_borrows {
144-
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id))))
136+
pub fn new(config: &MiriConfig) -> Self {
137+
let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
138+
let stacked_borrows = if config.stacked_borrows {
139+
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(
140+
config.tracked_pointer_tag,
141+
config.tracked_call_id,
142+
config.track_raw,
143+
))))
145144
} else {
146145
None
147146
};
@@ -150,8 +149,8 @@ impl MemoryExtra {
150149
intptrcast: Default::default(),
151150
extern_statics: FxHashMap::default(),
152151
rng: RefCell::new(rng),
153-
tracked_alloc_id,
154-
check_alignment,
152+
tracked_alloc_id: config.tracked_alloc_id,
153+
check_alignment: config.check_alignment,
155154
}
156155
}
157156

src/range_map.rs

+17-13
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ impl<T> RangeMap<T> {
6161
/// Provides read-only iteration over everything in the given range. This does
6262
/// *not* split items if they overlap with the edges. Do not use this to mutate
6363
/// through interior mutability.
64-
pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator<Item = &'a T> + 'a {
64+
///
65+
/// The iterator also provides the offset of the given element.
66+
pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator<Item = (Size, &'a T)> + 'a {
6567
let offset = offset.bytes();
6668
let len = len.bytes();
6769
// Compute a slice starting with the elements we care about.
@@ -75,7 +77,7 @@ impl<T> RangeMap<T> {
7577
};
7678
// The first offset that is not included any more.
7779
let end = offset + len;
78-
slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| &elem.data)
80+
slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| (Size::from_bytes(elem.range.start), &elem.data))
7981
}
8082

8183
pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
@@ -112,11 +114,13 @@ impl<T> RangeMap<T> {
112114
/// this will split entries in the map that are only partially hit by the given range,
113115
/// to make sure that when they are mutated, the effect is constrained to the given range.
114116
/// Moreover, this will opportunistically merge neighbouring equal blocks.
117+
///
118+
/// The iterator also provides the offset of the given element.
115119
pub fn iter_mut<'a>(
116120
&'a mut self,
117121
offset: Size,
118122
len: Size,
119-
) -> impl Iterator<Item = &'a mut T> + 'a
123+
) -> impl Iterator<Item = (Size, &'a mut T)> + 'a
120124
where
121125
T: Clone + PartialEq,
122126
{
@@ -197,7 +201,7 @@ impl<T> RangeMap<T> {
197201
// Now we yield the slice. `end` is inclusive.
198202
&mut self.v[first_idx..=end_idx]
199203
};
200-
slice.iter_mut().map(|elem| &mut elem.data)
204+
slice.iter_mut().map(|elem| (Size::from_bytes(elem.range.start), &mut elem.data))
201205
}
202206
}
203207

@@ -209,26 +213,26 @@ mod tests {
209213
fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
210214
(offset..offset + len)
211215
.into_iter()
212-
.map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|&t| t).unwrap())
216+
.map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap())
213217
.collect()
214218
}
215219

216220
#[test]
217221
fn basic_insert() {
218222
let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
219223
// Insert.
220-
for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) {
224+
for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) {
221225
*x = 42;
222226
}
223227
// Check.
224228
assert_eq!(to_vec(&map, 10, 1), vec![42]);
225229
assert_eq!(map.v.len(), 3);
226230

227231
// Insert with size 0.
228-
for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) {
232+
for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) {
229233
*x = 19;
230234
}
231-
for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) {
235+
for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) {
232236
*x = 19;
233237
}
234238
assert_eq!(to_vec(&map, 10, 2), vec![42, -1]);
@@ -238,16 +242,16 @@ mod tests {
238242
#[test]
239243
fn gaps() {
240244
let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
241-
for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) {
245+
for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) {
242246
*x = 42;
243247
}
244-
for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) {
248+
for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) {
245249
*x = 43;
246250
}
247251
assert_eq!(map.v.len(), 5);
248252
assert_eq!(to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]);
249253

250-
for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) {
254+
for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) {
251255
if *x < 42 {
252256
*x = 23;
253257
}
@@ -256,14 +260,14 @@ mod tests {
256260
assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]);
257261
assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]);
258262

259-
for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) {
263+
for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) {
260264
*x = 19;
261265
}
262266
assert_eq!(map.v.len(), 6);
263267
assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]);
264268
// Should be seeing two blocks with 19.
265269
assert_eq!(
266-
map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|&t| t).collect::<Vec<_>>(),
270+
map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|(_, &t)| t).collect::<Vec<_>>(),
267271
vec![19, 19]
268272
);
269273

0 commit comments

Comments
 (0)