blob: 3b196511b7e4686e246d2e0ec9f42753b2b26ffa (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#![warn(unsafe_code)]
#![warn(rust_2018_idioms, single_use_lifetimes)]
#![allow(dead_code)]
#![deny(safe_packed_borrows)]
use std::cell::Cell;
// Ensure that the compiler doesn't copy the fields
// of #[repr(packed)] types during drop, if the field has alignment 1
// (that is, any reference to the field is guaranteed to have proper alignment)
// We are currently unable to statically prevent the usage of #[pin_project]
// on #[repr(packed)] types composed entirely of fields of alignment 1.
// This shouldn't lead to undefined behavior, as long as the compiler doesn't
// try to move the field anyway during drop.
//
// This tests validates that the compiler is doing what we expect.
#[test]
fn weird_repr_packed() {
// We keep track of the field address during
// drop using a thread local, to avoid changing
// the layout of our #[repr(packed)] type.
thread_local! {
static FIELD_ADDR: Cell<usize> = Cell::new(0);
}
#[repr(packed)]
struct Foo {
field: u8,
}
impl Drop for Foo {
fn drop(&mut self) {
FIELD_ADDR.with(|f| {
f.set(&self.field as *const u8 as usize);
})
}
}
let field_addr = {
// We let this field drop by going out of scope,
// rather than explicitly calling drop(foo).
// Calling drop(foo) causes 'foo' to be moved
// into the 'drop' function, resulting in a different
// address.
let foo = Foo { field: 27 };
let field_addr = &foo.field as *const u8 as usize;
field_addr
};
assert_eq!(field_addr, FIELD_ADDR.with(|f| f.get()));
}
|