File: unaligned_references.rs

package info (click to toggle)
rustc 1.85.0%2Bdfsg3-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, forky, sid, trixie
  • size: 893,396 kB
  • sloc: xml: 158,127; python: 35,830; javascript: 19,497; cpp: 19,002; sh: 17,245; ansic: 13,127; asm: 4,376; makefile: 1,051; perl: 29; lisp: 29; ruby: 19; sql: 11
file content (142 lines) | stat: -rw-r--r-- 4,027 bytes parent folder | download | duplicates (4)
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

use std::fmt::Debug;
use std::mem::ManuallyDrop;

#[repr(packed)]
pub struct Good {
    data: u64,
    ptr: &'static u64,
    data2: [u64; 2],
    aligned: [u8; 32],
}

#[repr(packed(2))]
pub struct Packed2 {
    x: u32,
    y: u16,
    z: u8,
}

trait Foo {
    fn evil(&self);
}

// Test for #108122
#[automatically_derived]
impl Foo for Packed2 {
    fn evil(&self) {
        unsafe {
            &self.x; //~ ERROR reference to packed field
        }
    }
}

// Test for #115396
fn packed_dyn() {
    #[repr(packed)]
    struct Unaligned<T: ?Sized>(ManuallyDrop<T>);

    let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u64]));
    let foo: &Unaligned<dyn Debug> = &*local;
    println!("{:?}", &*foo.0); //~ ERROR reference to packed field
    let foo: &Unaligned<[u64]> = &*local;
    println!("{:?}", &*foo.0); //~ ERROR reference to packed field

    // Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.`
    let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u8]));
    let foo: &Unaligned<dyn Debug> = &*local;
    println!("{:?}", &*foo.0); //~ ERROR reference to packed field
    // However, we *can* know the alignment when looking at a slice.
    let foo: &Unaligned<[u8]> = &*local;
    println!("{:?}", &*foo.0); // no error!
}

// Test for #115396
fn packed_slice_behind_alias() {
    trait Mirror {
        type Assoc: ?Sized;
    }
    impl<T: ?Sized> Mirror for T {
        type Assoc = T;
    }

    struct W<T: ?Sized>(<T as Mirror>::Assoc);

    #[repr(packed)]
    struct Unaligned<T: ?Sized>(ManuallyDrop<W<T>>);

    // Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.`
    let ref local: Unaligned<[_; 3]> = Unaligned(ManuallyDrop::new(W([3, 5, 8u8])));
    let foo: &Unaligned<[u8]> = local;
    let x = &foo.0; // Fine, since the tail of `foo` is `[_]`
}

fn main() {
    unsafe {
        let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };

        let _ = &good.ptr; //~ ERROR reference to packed field
        let _ = &good.data; //~ ERROR reference to packed field
        // Error even when turned into raw pointer immediately.
        let _ = &good.data as *const _; //~ ERROR reference to packed field
        let _: *const _ = &good.data; //~ ERROR reference to packed field
        // Error on method call.
        let _ = good.data.clone(); //~ ERROR reference to packed field
        // Error for nested fields.
        let _ = &good.data2[0]; //~ ERROR reference to packed field

        let _ = &*good.ptr; // ok, behind a pointer
        let _ = &good.aligned; // ok, has align 1
        let _ = &good.aligned[2]; // ok, has align 1
    }

    unsafe {
        let packed2 = Packed2 { x: 0, y: 0, z: 0 };
        let _ = &packed2.x; //~ ERROR reference to packed field
        let _ = &packed2.y; // ok, has align 2 in packed(2) struct
        let _ = &packed2.z; // ok, has align 1
        packed2.evil();
    }

    unsafe {
        struct U16(u16);

        impl Drop for U16 {
            fn drop(&mut self) {
                println!("{:p}", self);
            }
        }

        struct HasDrop;

        impl Drop for HasDrop {
            fn drop(&mut self) {}
        }

        #[allow(unused)]
        struct Wrapper {
            a: U16,
            b: HasDrop,
        }
        #[allow(unused)]
        #[repr(packed(2))]
        struct Wrapper2 {
            a: U16,
            b: HasDrop,
        }

        // An outer struct with more restrictive packing than the inner struct -- make sure we
        // notice that!
        #[repr(packed)]
        struct Misalign<T>(u8, T);

        let m1 = Misalign(0, Wrapper { a: U16(10), b: HasDrop });
        let _ref = &m1.1.a; //~ ERROR reference to packed field

        let m2 = Misalign(0, Wrapper2 { a: U16(10), b: HasDrop });
        let _ref = &m2.1.a; //~ ERROR reference to packed field
    }
}