Skip to content

Commit 3c05276

Browse files
committed
restrict the valid range of references if -Z reference-niches is set
Note that this doesn't actually work at all, as many places in rustc assume that references only have the null niche.
1 parent 8b847ef commit 3c05276

File tree

2 files changed

+64
-11
lines changed

2 files changed

+64
-11
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,31 @@ impl TargetDataLayout {
354354
}
355355
}
356356

357+
/// Returns the theoretical maximum address.
358+
///
359+
/// Note that this doesn't take into account target-specific limitations.
360+
#[inline]
361+
pub fn max_address(&self) -> u64 {
362+
match self.pointer_size.bits() {
363+
16 => u16::MAX.into(),
364+
32 => u32::MAX.into(),
365+
64 => u64::MAX,
366+
bits => panic!("max_address: unknown pointer bit size {}", bits),
367+
}
368+
}
369+
370+
/// Returns the (inclusive) range of possible addresses for an allocation with
371+
/// the given size and alignment.
372+
///
373+
/// Note that this doesn't take into account target-specific limitations.
374+
#[inline]
375+
pub fn address_range_for(&self, size: Size, align: Align) -> (u64, u64) {
376+
let end = Size::from_bytes(self.max_address());
377+
let min = align.bytes();
378+
let max = (end - size).align_down_to(align).bytes();
379+
(min, max)
380+
}
381+
357382
#[inline]
358383
pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
359384
for &(size, align) in &self.vector_align {
@@ -481,6 +506,12 @@ impl Size {
481506
Size::from_bytes((self.bytes() + mask) & !mask)
482507
}
483508

509+
#[inline]
510+
pub fn align_down_to(self, align: Align) -> Size {
511+
let mask = align.bytes() - 1;
512+
Size::from_bytes(self.bytes() & !mask)
513+
}
514+
484515
#[inline]
485516
pub fn is_aligned(self, align: Align) -> bool {
486517
let mask = align.bytes() - 1;

compiler/rustc_ty_utils/src/layout.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ pub fn provide(providers: &mut Providers) {
3030

3131
#[instrument(skip(tcx), level = "debug")]
3232
fn reference_niches_policy<'tcx>(tcx: TyCtxt<'tcx>, _: LocalCrate) -> ReferenceNichePolicy {
33-
const DEFAULT: ReferenceNichePolicy = ReferenceNichePolicy { size: false, align: false };
34-
35-
tcx.sess.opts.unstable_opts.reference_niches.unwrap_or(DEFAULT)
33+
tcx.sess.opts.unstable_opts.reference_niches.unwrap_or(DEFAULT_REF_NICHES)
3634
}
3735

36+
/// The reference niche policy for builtin types, and for types in
37+
/// crates not specifying `-Z reference-niches`.
38+
const DEFAULT_REF_NICHES: ReferenceNichePolicy = ReferenceNichePolicy { size: false, align: false };
39+
3840
#[instrument(skip(tcx, query), level = "debug")]
3941
fn naive_layout_of<'tcx>(
4042
tcx: TyCtxt<'tcx>,
@@ -163,7 +165,6 @@ fn naive_layout_of_uncached<'tcx>(
163165
// Potentially-wide pointers.
164166
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
165167
let data_ptr = scalar(Pointer(AddressSpace::DATA));
166-
167168
if let Some(metadata) = ptr_metadata_scalar(cx, pointee)? {
168169
// Effectively a (ptr, meta) tuple.
169170
data_ptr
@@ -322,15 +323,36 @@ fn layout_of_uncached<'tcx>(
322323
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
323324
let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA));
324325
if !ty.is_unsafe_ptr() {
325-
match cx.naive_layout_of(pointee) {
326-
// TODO(reference_niches): actually use the naive layout to set
327-
// reference niches; the query is still kept to for testing purposes.
328-
Ok(_) => (),
326+
// Calling `layout_of` here would cause a query cycle for recursive types;
327+
// so use a conservative estimate that doesn't look past references.
328+
let naive = match cx.naive_layout_of(pointee) {
329+
Ok(n) => n.layout,
329330
// This can happen when computing the `SizeSkeleton` of a generic type.
330-
Err(LayoutError::Unknown(_)) => (),
331+
Err(LayoutError::Unknown(_)) => {
332+
// TODO(reference_niches): this is *very* incorrect, but we can't
333+
// return an error here; this would break transmute checks.
334+
// We need some other solution.
335+
NaiveLayout::EMPTY
336+
}
331337
Err(err) => return Err(err),
332-
}
333-
data_ptr.valid_range_mut().start = 1;
338+
};
339+
340+
let niches = match *pointee.kind() {
341+
ty::FnDef(def, ..)
342+
| ty::Foreign(def)
343+
| ty::Generator(def, ..)
344+
| ty::Closure(def, ..) => tcx.reference_niches_policy(def.krate),
345+
ty::Adt(def, _) => tcx.reference_niches_policy(def.did().krate),
346+
_ => DEFAULT_REF_NICHES,
347+
};
348+
349+
let (min_addr, max_addr) = dl.address_range_for(
350+
if niches.size { naive.min_size } else { Size::ZERO },
351+
if niches.align { naive.min_align } else { Align::ONE },
352+
);
353+
354+
*data_ptr.valid_range_mut() =
355+
WrappingRange { start: min_addr.into(), end: max_addr.into() };
334356
}
335357

336358
if let Some(metadata) = ptr_metadata_scalar(cx, pointee)? {

0 commit comments

Comments
 (0)