summaryrefslogtreecommitdiffstats
path: root/tests/ui/consts/const-eval/ub-incorrect-vtable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/consts/const-eval/ub-incorrect-vtable.rs')
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs
new file mode 100644
index 000000000..4bb30b75b
--- /dev/null
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs
@@ -0,0 +1,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() {}