Skip to content

Commit 5b66f27

Browse files
Use const_eval_limit instead of infinite loop detector
1 parent 7ceebd9 commit 5b66f27

File tree

3 files changed

+25
-73
lines changed

3 files changed

+25
-73
lines changed

src/librustc/mir/interpret/error.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,10 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
565565
pub enum ResourceExhaustionInfo {
566566
/// The stack grew too big.
567567
StackFrameLimitReached,
568-
/// The program ran into an infinite loop.
569-
InfiniteLoop,
568+
/// The program ran for too long.
569+
///
570+
/// The exact limit is set by the `const_eval_limit` attribute.
571+
TimeLimitReached,
570572
}
571573

572574
impl fmt::Debug for ResourceExhaustionInfo {
@@ -576,11 +578,7 @@ impl fmt::Debug for ResourceExhaustionInfo {
576578
StackFrameLimitReached => {
577579
write!(f, "reached the configured maximum number of stack frames")
578580
}
579-
InfiniteLoop => write!(
580-
f,
581-
"duplicate interpreter state observed here, const evaluation will never \
582-
terminate"
583-
),
581+
TimeLimitReached => write!(f, "exceeded interpreter time limit"),
584582
}
585583
}
586584
}

src/librustc_mir/const_eval/machine.rs

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use rustc::ty::layout::HasTyCtxt;
33
use rustc::ty::{self, Ty};
44
use std::borrow::{Borrow, Cow};
55
use std::collections::hash_map::Entry;
6-
use std::convert::TryFrom;
76
use std::hash::Hash;
87

98
use rustc_data_structures::fx::FxHashMap;
@@ -13,13 +12,13 @@ use rustc_span::source_map::Span;
1312
use rustc_span::symbol::Symbol;
1413

1514
use crate::interpret::{
16-
self, snapshot, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory,
17-
MemoryKind, OpTy, PlaceTy, Pointer, Scalar,
15+
self, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, OpTy,
16+
PlaceTy, Pointer, Scalar,
1817
};
1918

2019
use super::error::*;
2120

22-
impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
21+
impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter> {
2322
/// Evaluate a const function where all arguments (if any) are zero-sized types.
2423
/// The evaluation is memoized thanks to the query system.
2524
///
@@ -86,22 +85,13 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
8685
}
8786
}
8887

89-
/// The number of steps between loop detector snapshots.
90-
/// Should be a power of two for performance reasons.
91-
const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
92-
93-
// Extra machine state for CTFE, and the Machine instance
94-
pub struct CompileTimeInterpreter<'mir, 'tcx> {
95-
/// When this value is negative, it indicates the number of interpreter
96-
/// steps *until* the loop detector is enabled. When it is positive, it is
97-
/// the number of steps after the detector has been enabled modulo the loop
98-
/// detector period.
99-
pub(super) steps_since_detector_enabled: isize,
100-
101-
pub(super) is_detector_enabled: bool,
102-
103-
/// Extra state to detect loops.
104-
pub(super) loop_detector: snapshot::InfiniteLoopDetector<'mir, 'tcx>,
88+
/// Extra machine state for CTFE, and the Machine instance
89+
pub struct CompileTimeInterpreter {
90+
/// For now, the number of terminators that can be evaluated before we throw a resource
91+
/// exhuastion error.
92+
///
93+
/// Setting this to `0` disables the limit and allows the interpreter to run forever.
94+
pub steps_remaining: usize,
10595
}
10696

10797
#[derive(Copy, Clone, Debug)]
@@ -110,16 +100,9 @@ pub struct MemoryExtra {
110100
pub(super) can_access_statics: bool,
111101
}
112102

113-
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
103+
impl CompileTimeInterpreter {
114104
pub(super) fn new(const_eval_limit: usize) -> Self {
115-
let steps_until_detector_enabled =
116-
isize::try_from(const_eval_limit).unwrap_or(std::isize::MAX);
117-
118-
CompileTimeInterpreter {
119-
loop_detector: Default::default(),
120-
steps_since_detector_enabled: -steps_until_detector_enabled,
121-
is_detector_enabled: const_eval_limit != 0,
122-
}
105+
CompileTimeInterpreter { steps_remaining: const_eval_limit }
123106
}
124107
}
125108

@@ -173,8 +156,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
173156
}
174157
}
175158

176-
crate type CompileTimeEvalContext<'mir, 'tcx> =
177-
InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>;
159+
crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter>;
178160

179161
impl interpret::MayLeak for ! {
180162
#[inline(always)]
@@ -184,7 +166,7 @@ impl interpret::MayLeak for ! {
184166
}
185167
}
186168

187-
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
169+
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter {
188170
type MemoryKinds = !;
189171
type PointerTag = ();
190172
type ExtraFnVal = !;
@@ -346,26 +328,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
346328
}
347329

348330
fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
349-
if !ecx.machine.is_detector_enabled {
331+
// The step limit has already been hit in a previous call to `before_terminator`.
332+
if ecx.machine.steps_remaining == 0 {
350333
return Ok(());
351334
}
352335

353-
{
354-
let steps = &mut ecx.machine.steps_since_detector_enabled;
355-
356-
*steps += 1;
357-
if *steps < 0 {
358-
return Ok(());
359-
}
360-
361-
*steps %= DETECTOR_SNAPSHOT_PERIOD;
362-
if *steps != 0 {
363-
return Ok(());
364-
}
336+
ecx.machine.steps_remaining -= 1;
337+
if ecx.machine.steps_remaining == 0 {
338+
throw_exhaust!(TimeLimitReached)
365339
}
366340

367-
let span = ecx.frame().span;
368-
ecx.machine.loop_detector.observe_and_analyze(*ecx.tcx, span, &ecx.memory, &ecx.stack[..])
341+
Ok(())
369342
}
370343

371344
#[inline(always)]

src/librustc_mir/interpret/memory.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -112,25 +112,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M>
112112
}
113113
}
114114

115-
// FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead
116-
// carefully copy only the reachable parts.
117-
impl<'mir, 'tcx, M> Clone for Memory<'mir, 'tcx, M>
118-
where
119-
M: Machine<'mir, 'tcx, PointerTag = (), AllocExtra = ()>,
120-
M::MemoryExtra: Copy,
121-
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
122-
{
123-
fn clone(&self) -> Self {
124-
Memory {
125-
alloc_map: self.alloc_map.clone(),
126-
extra_fn_ptr_map: self.extra_fn_ptr_map.clone(),
127-
dead_alloc_map: self.dead_alloc_map.clone(),
128-
extra: self.extra,
129-
tcx: self.tcx,
130-
}
131-
}
132-
}
133-
134115
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
135116
pub fn new(tcx: TyCtxtAt<'tcx>, extra: M::MemoryExtra) -> Self {
136117
Memory {

0 commit comments

Comments
 (0)