Skip to content

Commit 722aabc

Browse files
committed
Check all dangling pointers in validation instead of in interning
1 parent 38a1733 commit 722aabc

File tree

7 files changed

+51
-34
lines changed

7 files changed

+51
-34
lines changed

compiler/rustc_const_eval/messages.ftl

-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ const_eval_dangling_int_pointer =
4949
const_eval_dangling_null_pointer =
5050
{$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance)
5151
52-
const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind}
5352
const_eval_dead_local =
5453
accessing a dead local variable
5554
const_eval_dealloc_immutable =

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ fn const_validate_mplace<'mir, 'tcx>(
403403
CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner }
404404
}
405405
};
406-
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)
406+
ecx.const_validate_operand(mplace, path, &mut ref_tracking, mode)
407407
// Instead of just reporting the `InterpError` via the usual machinery, we give a more targetted
408408
// error about the validation failure.
409409
.map_err(|error| report_validation_error(&ecx, error, alloc_id))?;

compiler/rustc_const_eval/src/errors.rs

-8
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,6 @@ use rustc_target::abi::{Size, WrappingRange};
1717

1818
use crate::interpret::InternKind;
1919

20-
#[derive(Diagnostic)]
21-
#[diag(const_eval_dangling_ptr_in_final)]
22-
pub(crate) struct DanglingPtrInFinal {
23-
#[primary_span]
24-
pub span: Span,
25-
pub kind: InternKind,
26-
}
27-
2820
#[derive(Diagnostic)]
2921
#[diag(const_eval_mutable_ptr_in_final)]
3022
pub(crate) struct MutablePtrInFinal {

compiler/rustc_const_eval/src/interpret/intern.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_span::sym;
2626

2727
use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
2828
use crate::const_eval;
29-
use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal};
29+
use crate::errors::MutablePtrInFinal;
3030

3131
pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
3232
'mir,
@@ -278,9 +278,7 @@ pub fn intern_const_alloc_recursive<
278278
continue;
279279
}
280280
just_interned.insert(alloc_id);
281-
todo.extend(intern_shallow(ecx, alloc_id).map_err(|()| {
282-
ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
283-
})?);
281+
todo.extend(intern_shallow(ecx, alloc_id).unwrap());
284282
}
285283
if found_bad_mutable_pointer {
286284
return Err(ecx

compiler/rustc_const_eval/src/interpret/validity.rs

+40-17
Original file line numberDiff line numberDiff line change
@@ -606,17 +606,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
606606
if place.layout.is_unsized() {
607607
self.check_wide_ptr_meta(place.meta(), place.layout)?;
608608
}
609-
if let Some(prov) = place.ptr().provenance {
610-
if let Some(alloc_id) = prov.get_alloc_id() {
611-
if let AllocKind::Dead = self.ecx.get_alloc_info(alloc_id).2 {
612-
throw_validation_failure!(
613-
self.path,
614-
DanglingPtrUseAfterFree {
615-
ptr_kind: PointerKind::Ref(Mutability::Not)
616-
}
617-
)
618-
}
619-
}
609+
if self.ref_tracking.is_some()
610+
&& let Some(alloc_id) = place.ptr().provenance.and_then(|p| p.get_alloc_id())
611+
&& let AllocKind::Dead = self.ecx.get_alloc_info(alloc_id).2
612+
{
613+
throw_validation_failure!(
614+
self.path,
615+
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(Mutability::Not) }
616+
)
620617
}
621618
Ok(true)
622619
}
@@ -988,15 +985,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
988985
path: Vec<PathElem>,
989986
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>,
990987
ctfe_mode: Option<CtfeValidationMode>,
991-
) -> InterpResult<'tcx> {
988+
) -> InterpResult<'tcx, Vec<PathElem>> {
992989
trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty);
993990

994991
// Construct a visitor
995992
let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self };
996993

997994
// Run it.
998995
match self.run_for_validation(|| visitor.visit_value(op)) {
999-
Ok(()) => Ok(()),
996+
Ok(()) => Ok(visitor.path),
1000997
// Pass through validation failures and "invalid program" issues.
1001998
Err(err)
1002999
if matches!(
@@ -1016,7 +1013,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10161013
}
10171014
}
10181015
}
1016+
}
10191017

1018+
impl<'mir, 'tcx> InterpCx<'mir, 'tcx, crate::const_eval::CompileTimeInterpreter<'mir, 'tcx>> {
10201019
/// This function checks the data at `op` to be const-valid.
10211020
/// `op` is assumed to cover valid memory if it is an indirect operand.
10221021
/// It will error if the bits at the destination do not match the ones described by the layout.
@@ -1030,14 +1029,38 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10301029
#[inline(always)]
10311030
pub(crate) fn const_validate_operand(
10321031
&self,
1033-
op: &OpTy<'tcx, M::Provenance>,
1032+
mplace: MPlaceTy<'tcx>,
10341033
path: Vec<PathElem>,
1035-
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>,
1034+
ref_tracking: &mut RefTracking<MPlaceTy<'tcx>, Vec<PathElem>>,
10361035
ctfe_mode: CtfeValidationMode,
10371036
) -> InterpResult<'tcx> {
1038-
self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode))
1037+
let prov = mplace.ptr().provenance;
1038+
let path = self.validate_operand_internal(
1039+
&mplace.into(),
1040+
path,
1041+
Some(ref_tracking),
1042+
Some(ctfe_mode),
1043+
)?;
1044+
1045+
// There was no error, so let's check the rest of the relocations in the pointed-to allocation for
1046+
// dangling pointers.
1047+
if let Some(prov) = prov
1048+
&& let Some((_, alloc)) = self.memory.alloc_map().get(&prov.alloc_id())
1049+
{
1050+
for (_, prov) in alloc.provenance().ptrs().iter() {
1051+
if let AllocKind::Dead = self.get_alloc_info(prov.alloc_id()).2 {
1052+
throw_validation_failure!(
1053+
path,
1054+
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(Mutability::Not) }
1055+
)
1056+
}
1057+
}
1058+
}
1059+
Ok(())
10391060
}
1061+
}
10401062

1063+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10411064
/// This function checks the data at `op` to be runtime-valid.
10421065
/// `op` is assumed to cover valid memory if it is an indirect operand.
10431066
/// It will error if the bits at the destination do not match the ones described by the layout.
@@ -1047,6 +1070,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10471070
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
10481071
// value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
10491072
// recurse through references which, for now, we don't want here, either.
1050-
self.validate_operand_internal(op, vec![], None, None)
1073+
self.validate_operand_internal(op, vec![], None, None).map(drop)
10511074
}
10521075
}

tests/ui/consts/dangling_raw_ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ union Union {
77
ptr: *const u32
88
}
99

10-
const BAR: Union = { //~ ERROR encountered dangling pointer in final value
10+
const BAR: Union = { //~ ERROR it is undefined behavior
1111
let x = 42;
1212
Union { ptr: &x }
1313
};

tests/ui/consts/dangling_raw_ptr.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ LL | const FOO: *const u32 = {
99
╾ALLOC0<imm>╼ │ ╾──────╼
1010
}
1111

12-
error: encountered dangling pointer in final value of constant
12+
error[E0080]: it is undefined behavior to use this value
1313
--> $DIR/dangling_raw_ptr.rs:10:1
1414
|
1515
LL | const BAR: Union = {
16-
| ^^^^^^^^^^^^^^^^
16+
| ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free)
17+
|
18+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
19+
= note: the raw bytes of the constant (size: 8, align: 8) {
20+
╾ALLOC1<imm>╼ │ ╾──────╼
21+
}
1722

1823
error: aborting due to 2 previous errors
1924

0 commit comments

Comments
 (0)