Skip to content

Commit f23fee1

Browse files
committed
Auto merge of rust-lang#130182 - RalfJung:ctfe-machine-no-padding-provenance-reset, r=<try>
interpreter typed copy validation: statically disable padding/provenance in CTFE machine Let's see if this fixes the perf impact in rust-lang#129778. r? `@saethlin`
2 parents 304b7f8 + 00e0059 commit f23fee1

File tree

5 files changed

+34
-26
lines changed

5 files changed

+34
-26
lines changed

compiler/rustc_const_eval/src/interpret/machine.rs

+4
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ pub trait Machine<'tcx>: Sized {
148148
/// already been checked before.
149149
const ALL_CONSTS_ARE_PRECHECKED: bool = true;
150150

151+
/// Whether *validated* typed copies should reset padding and provenance.
152+
/// Has no effect when `enforce_validity` returns `false`!
153+
const RESET_PROVENANCE_AND_PADDING: bool = false;
154+
151155
/// Whether memory accesses should be alignment-checked.
152156
fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool;
153157

compiler/rustc_const_eval/src/interpret/place.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,6 @@ where
608608
self.validate_operand(
609609
&dest.to_place(),
610610
M::enforce_validity_recursively(self, dest.layout()),
611-
/*reset_provenance_and_padding*/ true,
612611
)?;
613612
}
614613

@@ -821,14 +820,9 @@ where
821820
self.validate_operand(
822821
&dest.transmute(src.layout(), self)?,
823822
M::enforce_validity_recursively(self, src.layout()),
824-
/*reset_provenance_and_padding*/ true,
825823
)?;
826824
}
827-
self.validate_operand(
828-
&dest,
829-
M::enforce_validity_recursively(self, dest.layout()),
830-
/*reset_provenance_and_padding*/ true,
831-
)?;
825+
self.validate_operand(&dest, M::enforce_validity_recursively(self, dest.layout()))?;
832826
}
833827

834828
Ok(())

compiler/rustc_const_eval/src/interpret/validity.rs

+26-12
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,8 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
272272
ctfe_mode: Option<CtfeValidationMode>,
273273
ecx: &'rt mut InterpCx<'tcx, M>,
274274
/// Whether provenance should be reset outside of pointers (emulating the effect of a typed
275-
/// copy).
275+
/// copy). If this is `true`, then `M::RESET_PROVENANCE_AND_PADDING` is true, but not vice
276+
/// versa since we don't want to reset adding for recursive validation.
276277
reset_provenance_and_padding: bool,
277278
/// This tracks which byte ranges in this value contain data; the remaining bytes are padding.
278279
/// The ideal representation here would be pointer-length pairs, but to keep things more compact
@@ -416,7 +417,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
416417
let imm = self.read_immediate(val, expected)?;
417418
// Reset provenance: ensure slice tail metadata does not preserve provenance,
418419
// and ensure all pointers do not preserve partial provenance.
419-
if self.reset_provenance_and_padding {
420+
if self.reset_provenance_and_padding() {
420421
if matches!(imm.layout.abi, Abi::Scalar(..)) {
421422
// A thin pointer. If it has provenance, we don't have to do anything.
422423
// If it does not, ensure we clear the provenance in memory.
@@ -676,7 +677,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
676677
value: format!("{scalar:x}"),
677678
}
678679
);
679-
if self.reset_provenance_and_padding {
680+
if self.reset_provenance_and_padding() {
680681
self.ecx.clear_provenance(value)?;
681682
self.add_data_range_place(value);
682683
}
@@ -691,7 +692,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
691692
value: format!("{scalar:x}"),
692693
}
693694
);
694-
if self.reset_provenance_and_padding {
695+
if self.reset_provenance_and_padding() {
695696
self.ecx.clear_provenance(value)?;
696697
self.add_data_range_place(value);
697698
}
@@ -708,7 +709,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
708709
ExpectedKind::Int
709710
},
710711
)?;
711-
if self.reset_provenance_and_padding {
712+
if self.reset_provenance_and_padding() {
712713
self.ecx.clear_provenance(value)?;
713714
self.add_data_range_place(value);
714715
}
@@ -744,7 +745,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
744745
throw_validation_failure!(self.path, NullFnPtr);
745746
}
746747
}
747-
if self.reset_provenance_and_padding {
748+
if self.reset_provenance_and_padding() {
748749
// Make sure we do not preserve partial provenance. This matches the thin
749750
// pointer handling in `deref_pointer`.
750751
if matches!(scalar, Scalar::Int(..)) {
@@ -847,6 +848,13 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
847848
}
848849
}
849850

851+
#[inline(always)]
852+
fn reset_provenance_and_padding(&self) -> bool {
853+
// Make sure this becomes a constant `false` when `M::RESET_PADDING_AND_PROVENANCE` is `false`.
854+
// This way, all the padding/provenance reset code paths can be removed in the CTFE machine.
855+
M::RESET_PROVENANCE_AND_PADDING && self.reset_provenance_and_padding
856+
}
857+
850858
/// Add the given pointer-length pair to the "data" range of this visit.
851859
fn add_data_range(&mut self, ptr: Pointer<Option<M::Provenance>>, size: Size) {
852860
if let Some(data_bytes) = self.data_bytes.as_mut() {
@@ -882,6 +890,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
882890
}
883891

884892
fn reset_padding(&mut self, place: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
893+
if !M::RESET_PROVENANCE_AND_PADDING {
894+
return Ok(());
895+
}
885896
let Some(data_bytes) = self.data_bytes.as_mut() else { return Ok(()) };
886897
// Our value must be in memory, otherwise we would not have set up `data_bytes`.
887898
let mplace = self.ecx.force_allocation(place)?;
@@ -1122,7 +1133,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
11221133
}
11231134
}
11241135
}
1125-
if self.reset_provenance_and_padding
1136+
if self.reset_provenance_and_padding()
11261137
&& let Some(data_bytes) = self.data_bytes.as_mut()
11271138
{
11281139
let base_offset = Self::data_range_offset(self.ecx, val);
@@ -1255,7 +1266,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12551266

12561267
// Don't forget that these are all non-pointer types, and thus do not preserve
12571268
// provenance.
1258-
if self.reset_provenance_and_padding {
1269+
if self.reset_provenance_and_padding() {
12591270
// We can't share this with above as above, we might be looking at read-only memory.
12601271
let mut alloc = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)?.expect("we already excluded size 0");
12611272
alloc.clear_provenance()?;
@@ -1346,6 +1357,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
13461357

13471358
// Run the visitor.
13481359
match self.run_for_validation(|ecx| {
1360+
if reset_provenance_and_padding {
1361+
// Check the invariant relating `reset_provenance_and_padding` to this constant.
1362+
assert!(M::RESET_PROVENANCE_AND_PADDING);
1363+
}
13491364
let reset_padding = reset_provenance_and_padding && {
13501365
// Check if `val` is actually stored in memory. If not, padding is not even
13511366
// represented and we need not reset it.
@@ -1409,7 +1424,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14091424
path,
14101425
Some(ref_tracking),
14111426
Some(ctfe_mode),
1412-
/*reset_provenance*/ false,
1427+
/*reset_provenance_and_padding*/ false,
14131428
)
14141429
}
14151430

@@ -1421,7 +1436,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14211436
&mut self,
14221437
val: &PlaceTy<'tcx, M::Provenance>,
14231438
recursive: bool,
1424-
reset_provenance_and_padding: bool,
14251439
) -> InterpResult<'tcx> {
14261440
// Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
14271441
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
@@ -1432,7 +1446,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14321446
vec![],
14331447
None,
14341448
None,
1435-
reset_provenance_and_padding,
1449+
M::RESET_PROVENANCE_AND_PADDING,
14361450
);
14371451
}
14381452
// Do a recursive check.
@@ -1442,7 +1456,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14421456
vec![],
14431457
Some(&mut ref_tracking),
14441458
None,
1445-
reset_provenance_and_padding,
1459+
M::RESET_PROVENANCE_AND_PADDING,
14461460
)?;
14471461
while let Some((mplace, path)) = ref_tracking.todo.pop() {
14481462
// Things behind reference do *not* have the provenance reset.

compiler/rustc_const_eval/src/util/check_validity_requirement.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,7 @@ fn check_validity_requirement_strict<'tcx>(
6767
// due to this.
6868
// The value we are validating is temporary and discarded at the end of this function, so
6969
// there is no point in reseting provenance and padding.
70-
Ok(cx
71-
.validate_operand(
72-
&allocated.into(),
73-
/*recursive*/ false,
74-
/*reset_provenance_and_padding*/ false,
75-
)
76-
.is_ok())
70+
Ok(cx.validate_operand(&allocated.into(), /*recursive*/ false).is_ok())
7771
}
7872

7973
/// Implements the 'lax' (default) version of the [`check_validity_requirement`] checks; see that

src/tools/miri/src/machine.rs

+2
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
889889

890890
const PANIC_ON_ALLOC_FAIL: bool = false;
891891

892+
const RESET_PROVENANCE_AND_PADDING: bool = true;
893+
892894
#[inline(always)]
893895
fn enforce_alignment(ecx: &MiriInterpCx<'tcx>) -> bool {
894896
ecx.machine.check_alignment != AlignmentCheck::None

0 commit comments

Comments
 (0)