Skip to content

Commit d230ce5

Browse files
authored
Rollup merge of rust-lang#71140 - oli-obk:static_cycle, r=RalfJung
[breaking change] Disallow statics initializing themselves fixes rust-lang#71078 Self-initialization is unsound because it breaks privacy assumptions that unsafe code can make. In ```rust pub mod foo { #[derive(Debug, Copy, Clone)] pub struct Foo { x: (), } } pub static FOO: foo::Foo = FOO; ``` unsafe could could expect that ony functions inside the `foo` module were able to create a value of type `Foo`.
2 parents 31f7b11 + e4ab4ee commit d230ce5

File tree

4 files changed

+44
-10
lines changed

4 files changed

+44
-10
lines changed

src/librustc_mir/interpret/memory.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
400400

401401
// We can still be zero-sized in this branch, in which case we have to
402402
// return `None`.
403-
if size.bytes() == 0 { None } else { Some(ptr) }
403+
if size.bytes() == 0 {
404+
// We may be reading from a static.
405+
// In order to ensure that `static FOO: Type = FOO;` causes a cycle error
406+
// instead of magically pulling *any* ZST value from the ether, we need to
407+
// actually access the referenced allocation. The caller is likely
408+
// to short-circuit on `None`, so we trigger the access here to
409+
// make sure it happens.
410+
self.get_raw(ptr.alloc_id)?;
411+
None
412+
} else {
413+
Some(ptr)
414+
}
404415
}
405416
})
406417
}

src/librustc_mir/interpret/operand.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
248248
}
249249
};
250250

251+
let alloc = self.memory.get_raw(ptr.alloc_id)?;
252+
251253
match mplace.layout.abi {
252254
Abi::Scalar(..) => {
253-
let scalar = self.memory.get_raw(ptr.alloc_id)?.read_scalar(
254-
self,
255-
ptr,
256-
mplace.layout.size,
257-
)?;
255+
let scalar = alloc.read_scalar(self, ptr, mplace.layout.size)?;
258256
Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }))
259257
}
260258
Abi::ScalarPair(ref a, ref b) => {
@@ -267,8 +265,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
267265
let b_offset = a_size.align_to(b.align(self).abi);
268266
assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields
269267
let b_ptr = ptr.offset(b_offset, self)?;
270-
let a_val = self.memory.get_raw(ptr.alloc_id)?.read_scalar(self, a_ptr, a_size)?;
271-
let b_val = self.memory.get_raw(ptr.alloc_id)?.read_scalar(self, b_ptr, b_size)?;
268+
let a_val = alloc.read_scalar(self, a_ptr, a_size)?;
269+
let b_val = alloc.read_scalar(self, b_ptr, b_size)?;
272270
Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout }))
273271
}
274272
_ => Ok(None),

src/test/ui/consts/recursive-zst-static.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
// build-pass
1+
// This test ensures that we do not allow ZST statics to initialize themselves without ever
2+
// actually creating a value of that type. This is important, as the ZST may have private fields
3+
// that users can reasonably expect to only get initialized by their own code. Thus unsafe code
4+
// can depend on this fact and will thus do unsound things when it is violated.
5+
// See https://github.com/rust-lang/rust/issues/71078 for more details.
26

3-
static FOO: () = FOO;
7+
static FOO: () = FOO; //~ cycle detected when const-evaluating `FOO`
48

59
fn main() {
610
FOO
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0391]: cycle detected when const-evaluating `FOO`
2+
--> $DIR/recursive-zst-static.rs:7:18
3+
|
4+
LL | static FOO: () = FOO;
5+
| ^^^
6+
|
7+
note: ...which requires const-evaluating `FOO`...
8+
--> $DIR/recursive-zst-static.rs:7:1
9+
|
10+
LL | static FOO: () = FOO;
11+
| ^^^^^^^^^^^^^^^^^^^^^
12+
= note: ...which again requires const-evaluating `FOO`, completing the cycle
13+
note: cycle used when const-evaluating + checking `FOO`
14+
--> $DIR/recursive-zst-static.rs:7:1
15+
|
16+
LL | static FOO: () = FOO;
17+
| ^^^^^^^^^^^^^^^^^^^^^
18+
19+
error: aborting due to previous error
20+
21+
For more information about this error, try `rustc --explain E0391`.

0 commit comments

Comments
 (0)