Skip to content

Commit

Permalink
codegen: panic when trying to compute size/align of extern type
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Dec 12, 2023
1 parent 8b1ba11 commit b1613eb
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 25 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ pub mod codegen_attrs;
pub mod common;
pub mod debuginfo;
pub mod errors;
pub mod glue;
pub mod meth;
pub mod mir;
pub mod mono_item;
pub mod size_of_val;
pub mod target_features;
pub mod traits;

Expand Down
22 changes: 9 additions & 13 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use super::FunctionCx;
use crate::common::IntPredicate;
use crate::errors;
use crate::errors::InvalidMonomorphization;
use crate::glue;
use crate::meth;
use crate::size_of_val;
use crate::traits::*;
use crate::MemFlags;

Expand Down Expand Up @@ -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::size_of_val => {
let tp_ty = fn_args.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val {
let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
llsize
} else {
bx.const_usize(bx.layout_of(tp_ty).size.bytes())
}
let 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
}
sym::min_align_of_val => {
let tp_ty = fn_args.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val {
let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
llalign
} else {
bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes())
}
let 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
}
sym::vtable_size | sym::vtable_align => {
let vtable = args[0].immediate();
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::place::PlaceRef;
use super::{FunctionCx, LocalRef};

use crate::base;
use crate::glue;
use crate::size_of_val;
use crate::traits::*;
use crate::MemFlags;

Expand Down Expand Up @@ -466,13 +466,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
.ty;

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
// doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
// 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 align_minus_1 = bx.sub(align, one);
let size_extra = bx.add(size, align_minus_1);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::operand::OperandValue;
use super::{FunctionCx, LocalRef};

use crate::common::IntPredicate;
use crate::glue;
use crate::size_of_val;
use crate::traits::*;

use rustc_middle::mir;
Expand Down Expand Up @@ -179,7 +179,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
let unaligned_offset = bx.cx().const_usize(offset.bytes());

// 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.
if let ty::Adt(def, _) = self.layout.ty.kind()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//!
//
// Code relating to drop glue.
//! Computing the size and alignment of a value.

use crate::common;
use crate::common::IntPredicate;
use crate::meth;
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_target::abi::WrappingRange;

Expand All @@ -14,7 +15,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
info: Option<Bx::Value>,
) -> (Bx::Value, Bx::Value) {
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() {
let size = bx.const_usize(layout.size.bytes());
let align = bx.const_usize(layout.align.abi.bytes());
Expand Down Expand Up @@ -51,7 +52,31 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
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.
// 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.
Expand Down Expand Up @@ -122,5 +147,6 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

(size, align)
}
_ => bug!("size_and_align_of_dst: {t} not supported"),
}
}
5 changes: 4 additions & 1 deletion tests/ui/extern/extern-types-size_of_val.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// run-pass
// run-fail
// check-run-results
// normalize-stderr-test "panicking\.rs:\d+:\d+:" -> "panicking.rs:"
#![feature(extern_types)]

use std::mem::{align_of_val, size_of_val};
Expand All @@ -10,6 +12,7 @@ extern "C" {
fn main() {
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!(align_of_val(x), 1);
}
4 changes: 4 additions & 0 deletions tests/ui/extern/extern-types-size_of_val.run.stderr
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit b1613eb

Please sign in to comment.