codegen: panic when trying to compute size/align of extern type

This commit is contained in:
Ralf Jung 2023-12-02 12:25:01 +01:00
parent 8b1ba11cb1
commit b1613ebc43
7 changed files with 54 additions and 25 deletions

View File

@ -51,10 +51,10 @@ pub mod codegen_attrs;
pub mod common; pub mod common;
pub mod debuginfo; pub mod debuginfo;
pub mod errors; pub mod errors;
pub mod glue;
pub mod meth; pub mod meth;
pub mod mir; pub mod mir;
pub mod mono_item; pub mod mono_item;
pub mod size_of_val;
pub mod target_features; pub mod target_features;
pub mod traits; pub mod traits;

View File

@ -4,8 +4,8 @@ use super::FunctionCx;
use crate::common::IntPredicate; use crate::common::IntPredicate;
use crate::errors; use crate::errors;
use crate::errors::InvalidMonomorphization; use crate::errors::InvalidMonomorphization;
use crate::glue;
use crate::meth; use crate::meth;
use crate::size_of_val;
use crate::traits::*; use crate::traits::*;
use crate::MemFlags; use crate::MemFlags;
@ -88,21 +88,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::va_end => bx.va_end(args[0].immediate()), sym::va_end => bx.va_end(args[0].immediate()),
sym::size_of_val => { sym::size_of_val => {
let tp_ty = fn_args.type_at(0); let tp_ty = fn_args.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val { let meta =
let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
llsize llsize
} else {
bx.const_usize(bx.layout_of(tp_ty).size.bytes())
}
} }
sym::min_align_of_val => { sym::min_align_of_val => {
let tp_ty = fn_args.type_at(0); let tp_ty = fn_args.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val { let meta =
let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
llalign llalign
} else {
bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes())
}
} }
sym::vtable_size | sym::vtable_align => { sym::vtable_size | sym::vtable_align => {
let vtable = args[0].immediate(); let vtable = args[0].immediate();

View File

@ -2,7 +2,7 @@ use super::place::PlaceRef;
use super::{FunctionCx, LocalRef}; use super::{FunctionCx, LocalRef};
use crate::base; use crate::base;
use crate::glue; use crate::size_of_val;
use crate::traits::*; use crate::traits::*;
use crate::MemFlags; use crate::MemFlags;
@ -466,13 +466,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
.ty; .ty;
let OperandValue::Ref(llptr, Some(llextra), _) = self else { let OperandValue::Ref(llptr, Some(llextra), _) = self else {
bug!("store_unsized called with a sized value") bug!("store_unsized called with a sized value (or with an extern type)")
}; };
// Allocate an appropriate region on the stack, and copy the value into it. Since alloca // Allocate an appropriate region on the stack, and copy the value into it. Since alloca
// doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the // doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
// pointer manually. // pointer manually.
let (size, align) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); let (size, align) = size_of_val::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
let one = bx.const_usize(1); let one = bx.const_usize(1);
let align_minus_1 = bx.sub(align, one); let align_minus_1 = bx.sub(align, one);
let size_extra = bx.add(size, align_minus_1); let size_extra = bx.add(size, align_minus_1);

View File

@ -2,7 +2,7 @@ use super::operand::OperandValue;
use super::{FunctionCx, LocalRef}; use super::{FunctionCx, LocalRef};
use crate::common::IntPredicate; use crate::common::IntPredicate;
use crate::glue; use crate::size_of_val;
use crate::traits::*; use crate::traits::*;
use rustc_middle::mir; use rustc_middle::mir;
@ -179,7 +179,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
let unaligned_offset = bx.cx().const_usize(offset.bytes()); let unaligned_offset = bx.cx().const_usize(offset.bytes());
// Get the alignment of the field // Get the alignment of the field
let (_, mut unsized_align) = glue::size_and_align_of_dst(bx, field.ty, meta); let (_, mut unsized_align) = size_of_val::size_and_align_of_dst(bx, field.ty, meta);
// For packed types, we need to cap alignment. // For packed types, we need to cap alignment.
if let ty::Adt(def, _) = self.layout.ty.kind() if let ty::Adt(def, _) = self.layout.ty.kind()

View File

@ -1,10 +1,11 @@
//! //! Computing the size and alignment of a value.
//
// Code relating to drop glue.
use crate::common;
use crate::common::IntPredicate; use crate::common::IntPredicate;
use crate::meth; use crate::meth;
use crate::traits::*; use crate::traits::*;
use rustc_hir::LangItem;
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_target::abi::WrappingRange; use rustc_target::abi::WrappingRange;
@ -14,7 +15,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
info: Option<Bx::Value>, info: Option<Bx::Value>,
) -> (Bx::Value, Bx::Value) { ) -> (Bx::Value, Bx::Value) {
let layout = bx.layout_of(t); let layout = bx.layout_of(t);
debug!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout); trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout);
if layout.is_sized() { if layout.is_sized() {
let size = bx.const_usize(layout.size.bytes()); let size = bx.const_usize(layout.size.bytes());
let align = bx.const_usize(layout.align.abi.bytes()); let align = bx.const_usize(layout.align.abi.bytes());
@ -51,7 +52,31 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx.const_usize(unit.align.abi.bytes()), bx.const_usize(unit.align.abi.bytes()),
) )
} }
_ => { ty::Foreign(_) => {
// `extern` type. We cannot compute the size, so panic.
let msg_str = with_no_visible_paths!({
with_no_trimmed_paths!({
format!("attempted to compute the size or alignment of extern type `{t}`")
})
});
let msg = bx.const_str(&msg_str);
// Obtain the panic entry point.
let (fn_abi, llfn) = common::build_langcall(bx, None, LangItem::PanicNounwind);
// Generate the call.
// Cannot use `do_call` since we don't have a MIR terminator so we can't create a `TerminationCodegenHelper`.
// (But we are in good company, this code is duplicated plenty of times.)
let fn_ty = bx.fn_decl_backend_type(fn_abi);
bx.call(fn_ty, /* fn_attrs */ None, Some(fn_abi), llfn, &[msg.0, msg.1], None);
// This function does not return so we can now return whatever we want.
let size = bx.const_usize(layout.size.bytes());
let align = bx.const_usize(layout.align.abi.bytes());
(size, align)
}
ty::Adt(..) | ty::Tuple(..) => {
// First get the size of all statically known fields. // First get the size of all statically known fields.
// Don't use size_of because it also rounds up to alignment, which we // Don't use size_of because it also rounds up to alignment, which we
// want to avoid, as the unsized field's alignment could be smaller. // want to avoid, as the unsized field's alignment could be smaller.
@ -122,5 +147,6 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
(size, align) (size, align)
} }
_ => bug!("size_and_align_of_dst: {t} not supported"),
} }
} }

View File

@ -1,4 +1,6 @@
// run-pass // run-fail
// check-run-results
// normalize-stderr-test "panicking\.rs:\d+:\d+:" -> "panicking.rs:"
#![feature(extern_types)] #![feature(extern_types)]
use std::mem::{align_of_val, size_of_val}; use std::mem::{align_of_val, size_of_val};
@ -10,6 +12,7 @@ extern "C" {
fn main() { fn main() {
let x: &A = unsafe { &*(1usize as *const A) }; let x: &A = unsafe { &*(1usize as *const A) };
// These don't have a dynamic size, so this should panic.
assert_eq!(size_of_val(x), 0); assert_eq!(size_of_val(x), 0);
assert_eq!(align_of_val(x), 1); assert_eq!(align_of_val(x), 1);
} }

View File

@ -0,0 +1,4 @@
thread 'main' panicked at library/core/src/panicking.rs:
attempted to compute the size or alignment of extern type `A`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread caused non-unwinding panic. aborting.