From cae1918b2939824e4dbbba003099c0ccf21715e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Sat, 12 Jun 2021 13:13:38 +0200 Subject: [PATCH] Turn incorrect vtable size/alignment errors into hard const-UB errors They were "freeform const UB" error message, but could reach validation and trigger ICEs there. We now catch them during validation to avoid that. --- compiler/rustc_middle/src/mir/interpret/error.rs | 12 ++++++++++-- compiler/rustc_mir/src/interpret/traits.rs | 13 +++++-------- compiler/rustc_mir/src/interpret/validity.rs | 6 +++++- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 65d9c1dd90efb..aca39d438c103 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -227,7 +227,11 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Invalid metadata in a wide pointer (using `str` to avoid allocations). InvalidMeta(&'static str), /// Invalid drop function in vtable. - InvalidDropFn(FnSig<'tcx>), + InvalidVtableDropFn(FnSig<'tcx>), + /// Invalid size in a vtable: too large. + InvalidVtableSize, + /// Invalid alignment in a vtable: too large, or not a power of 2. + InvalidVtableAlignment(String), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -287,11 +291,15 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg), - InvalidDropFn(sig) => write!( + InvalidVtableDropFn(sig) => write!( f, "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type", sig ), + InvalidVtableSize => { + write!(f, "invalid vtable: size is bigger than largest supported object") + } + InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg), UnterminatedCString(p) => write!( f, "reading a null-terminated string starting at {} with no null found before end of allocation", diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index d0c04b5b414eb..9a59161f08f50 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -137,9 +137,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let args = fn_sig.inputs(); if args.len() != 1 { - throw_ub!(InvalidDropFn(fn_sig)); + throw_ub!(InvalidVtableDropFn(fn_sig)); } - let ty = args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidDropFn(fn_sig)))?.ty; + let ty = + args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty; Ok((drop_instance, ty)) } @@ -158,14 +159,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size = u64::try_from(self.force_bits(size, pointer_size)?).unwrap(); let align = vtable.read_ptr_sized(pointer_size * 2)?.check_init()?; let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap(); - let align = Align::from_bytes(align) - .map_err(|e| err_ub_format!("invalid vtable: alignment {}", e))?; + let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; if size >= self.tcx.data_layout.obj_size_bound() { - throw_ub_format!( - "invalid vtable: \ - size is bigger than largest supported object" - ); + throw_ub!(InvalidVtableSize); } Ok((Size::from_bytes(size), align)) } diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index fb165a991bceb..c9ebffe8d1cf4 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -349,12 +349,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' err_ub!(InvalidFunctionPointer(..)) | err_unsup!(ReadBytesAsPointer) => { "invalid drop function pointer in vtable (not pointing to a function)" }, - err_ub!(InvalidDropFn(..)) => + err_ub!(InvalidVtableDropFn(..)) => { "invalid drop function pointer in vtable (function has incompatible signature)" }, ); try_validation!( self.ecx.read_size_and_align_from_vtable(vtable), self.path, + err_ub!(InvalidVtableSize) => + { "invalid vtable: size is bigger than largest supported object" }, + err_ub!(InvalidVtableAlignment(msg)) => + { "invalid vtable: alignment {}", msg }, err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, ); // FIXME: More checks for the vtable.