Skip to content

Commit 0a2bd28

Browse files
RalfJungMark-Simulacrum
authored andcommitted
fix cycle when looking up size and align of a static
1 parent 2c0bc3d commit 0a2bd28

File tree

3 files changed

+41
-22
lines changed

3 files changed

+41
-22
lines changed

src/librustc_mir/interpret/machine.rs

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ pub trait AllocMap<K: Hash + Eq, V> {
5454
k: K,
5555
vacant: impl FnOnce() -> Result<V, E>
5656
) -> Result<&mut V, E>;
57+
58+
/// Read-only lookup.
59+
fn get(&self, k: K) -> Option<&V> {
60+
self.get_or(k, || Err(())).ok()
61+
}
5762
}
5863

5964
/// Methods of this trait signifies a point where CTFE evaluation would fail

src/librustc_mir/interpret/memory.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -492,13 +492,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
492492
id: AllocId,
493493
liveness: AllocCheck,
494494
) -> InterpResult<'static, (Size, Align)> {
495-
if let Ok(alloc) = self.get(id) {
495+
// # Regular allocations
496+
// Don't use `self.get` here as that will
497+
// a) cause cycles in case `id` refers to a static
498+
// b) duplicate a static's allocation in miri
499+
if let Some((_, alloc)) = self.alloc_map.get(id) {
496500
return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
497501
}
498-
// can't do this in the match argument, we may get cycle errors since the lock would get
499-
// dropped after the match.
502+
503+
// # Statics and function pointers
504+
// Can't do this in the match argument, we may get cycle errors since the lock would
505+
// be held throughout the match.
500506
let alloc = self.tcx.alloc_map.lock().get(id);
501-
// Could also be a fn ptr or extern static
502507
match alloc {
503508
Some(GlobalAlloc::Function(..)) => {
504509
if let AllocCheck::Dereferencable = liveness {
@@ -507,28 +512,26 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
507512
} else {
508513
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
509514
}
510-
}
511-
// `self.get` would also work, but can cause cycles if a static refers to itself
515+
},
512516
Some(GlobalAlloc::Static(did)) => {
513-
// The only way `get` couldn't have worked here is if this is an extern static
514-
assert!(self.tcx.is_foreign_item(did));
515-
// Use size and align of the type
517+
// Use size and align of the type.
516518
let ty = self.tcx.type_of(did);
517519
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
518520
Ok((layout.size, layout.align.abi))
519-
}
520-
_ => {
521-
if let Ok(alloc) = self.get(id) {
522-
Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align))
523-
}
524-
else if let AllocCheck::MaybeDead = liveness {
525-
// Deallocated pointers are allowed, we should be able to find
526-
// them in the map.
527-
Ok(*self.dead_alloc_map.get(&id)
528-
.expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
529-
} else {
530-
err!(DanglingPointerDeref)
531-
}
521+
},
522+
Some(GlobalAlloc::Memory(alloc)) =>
523+
// Need to duplicate the logic here, because the global allocations have
524+
// different associated types than the interpreter-local ones.
525+
Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
526+
// The rest must be dead.
527+
None => if let AllocCheck::MaybeDead = liveness {
528+
// Deallocated pointers are allowed, we should be able to find
529+
// them in the map.
530+
Ok(*self.dead_alloc_map.get(&id)
531+
.expect("deallocated pointers should all be recorded in \
532+
`dead_alloc_map`"))
533+
} else {
534+
err!(DanglingPointerDeref)
532535
},
533536
}
534537
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// compile-pass
2+
3+
struct Foo {
4+
foo: Option<&'static Foo>
5+
}
6+
7+
static FOO: Foo = Foo {
8+
foo: Some(&FOO),
9+
};
10+
11+
fn main() {}

0 commit comments

Comments
 (0)