Skip to content

Commit d2a8424

Browse files
committed
Ensure that Layout not matching the intrinsic's expectation will loudly and clearly ICE and fail library tests.
1 parent 062d4f3 commit d2a8424

2 files changed

Lines changed: 42 additions & 2 deletions

File tree

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_abi::{Align, FieldIdx, WrappingRange};
1+
use rustc_abi::{Align, FIRST_VARIANT, FieldIdx, WrappingRange};
22
use rustc_middle::mir::SourceInfo;
33
use rustc_middle::ty::{self, Ty, TyCtxt};
44
use rustc_middle::{bug, span_bug};
@@ -157,7 +157,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
157157
sym::size_of_val => llsize,
158158
sym::align_of_val => llalign,
159159
sym::layout_of_val => {
160-
// Use the builder so we're insulated from the in-memory field order
160+
// The builder insulates us from in-memory order, but double-check declared order
161+
debug_assert!({
162+
let layout_adt = result.layout.ty.ty_adt_def().unwrap();
163+
let layout_fields = layout_adt.variant(FIRST_VARIANT).fields.as_slice();
164+
if let [size, align] = &layout_fields.raw
165+
&& size.name == sym::size
166+
&& align.name == sym::align
167+
{
168+
true
169+
} else {
170+
false
171+
}
172+
});
173+
161174
let mut builder = OperandRefBuilder::<'_, Bx::Value>::new(result.layout);
162175
builder.insert_imm(FieldIdx::from_u32(0), llsize);
163176
builder.insert_imm(FieldIdx::from_u32(1), llalign);

library/core/src/alloc/layout.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ use crate::{assert_unsafe_precondition, fmt, mem};
2626
/// requirements, or use the more lenient `Allocator` interface.)
2727
#[stable(feature = "alloc_layout", since = "1.28.0")]
2828
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
29+
// BEWARE! The implementation of the `layout_of_val` intrinsic is coupled to the
30+
// declared order of these fields. As a reminder, you'll also get a (debug-only)
31+
// ICE if you change their names, though you can easily update that expectation.
2932
#[lang = "alloc_layout"]
3033
pub struct Layout {
3134
// size of the requested block of memory, measured in bytes.
@@ -247,6 +250,30 @@ impl Layout {
247250
///
248251
/// [trait object]: ../../book/ch17-02-trait-objects.html
249252
/// [extern type]: ../../unstable-book/language-features/extern-types.html
253+
///
254+
/// # Examples
255+
///
256+
/// ```
257+
/// #![feature(layout_for_ptr)]
258+
///
259+
/// use std::alloc::Layout;
260+
/// use std::ptr;
261+
///
262+
/// let arbitrary = ptr::without_provenance::<[u16; 3]>(123456);
263+
/// assert_eq!(
264+
/// // SAFETY: for a sized pointee, the function is always sound.
265+
/// unsafe { Layout::for_value_raw(arbitrary) },
266+
/// Layout::from_size_align(6, 2).unwrap(),
267+
/// );
268+
///
269+
/// let slice = ptr::slice_from_raw_parts(arbitrary, 789);
270+
/// assert_eq!(
271+
/// // SAFETY: with a slice pointee, this is sound because the length
272+
/// // is short enough that size in bytes doesn't overflow isize::MAX.
273+
/// unsafe { Layout::for_value_raw(slice) },
274+
/// Layout::from_size_align(6 * 789, 2).unwrap(),
275+
/// );
276+
/// ```
250277
#[unstable(feature = "layout_for_ptr", issue = "69835")]
251278
#[must_use]
252279
#[inline]

0 commit comments

Comments
 (0)