summaryrefslogtreecommitdiffstats
path: root/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs
blob: 4bb30b75bc8eb657fb6b0f21e093dbda598ed750 (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
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
// This test contains code with incorrect vtables in a const context:
// - from issue 86132: a trait object with invalid alignment caused an ICE in const eval, and now
//   triggers an error
// - a similar test that triggers a previously-untested const UB error: emitted close to the above
//   error, it checks the correctness of the size
//
// As is, this code will only hard error when the constants are used, and the errors are emitted via
// the `#[allow]`-able `const_err` lint. However, if the transparent wrapper technique to prevent
// reborrows is used -- from `ub-wide-ptr.rs` -- these two errors reach validation and would trigger
// ICEs as tracked by #86193. So we also use the transparent wrapper to verify proper validation
// errors are emitted instead of ICEs.

// stderr-per-bitwidth
// normalize-stderr-test "alloc\d+" -> "allocN"

trait Trait {}

const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
    unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
//~^ ERROR evaluation of constant value failed
//~| does not point to a vtable

const INVALID_VTABLE_SIZE: &dyn Trait =
    unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
//~^ ERROR evaluation of constant value failed
//~| does not point to a vtable

#[repr(transparent)]
struct W<T>(T);

fn drop_me(_: *mut usize) {}

const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
    unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
//~^^ ERROR it is undefined behavior to use this value
//~| expected a vtable pointer

const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
    unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
//~^^ ERROR it is undefined behavior to use this value
//~| expected a vtable pointer

// Even if the vtable has a fn ptr and a reasonable size+align, it still does not work.
const INVALID_VTABLE_UB: W<&dyn Trait> =
    unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1usize))) };
//~^^ ERROR it is undefined behavior to use this value
//~| expected a vtable pointer

// Trying to access the data in a vtable does not work, either.

#[derive(Copy, Clone)]
struct Wide<'a>(&'a Foo, &'static VTable);

struct VTable {
    drop: Option<for<'a> fn(&'a mut Foo)>,
    size: usize,
    align: usize,
    bar: for<'a> fn(&'a Foo) -> u32,
}

trait Bar {
    fn bar(&self) -> u32;
}

struct Foo {
    foo: u32,
    bar: bool,
}

impl Bar for Foo {
    fn bar(&self) -> u32 {
        self.foo
    }
}

impl Drop for Foo {
    fn drop(&mut self) {
        assert!(!self.bar);
        self.bar = true;
        println!("dropping Foo");
    }
}

#[repr(C)]
union Transmute<T: Copy, U: Copy> {
    t: T,
    u: U,
}

const FOO: &dyn Bar = &Foo { foo: 128, bar: false };
const G: Wide = unsafe { Transmute { t: FOO }.u };
//~^ ERROR it is undefined behavior to use this value
//~| encountered a dangling reference
// (it is dangling because vtables do not contain memory that can be dereferenced)

fn main() {}