@@ -3,11 +3,14 @@ use std::hash::{Hash, Hasher};
33use rustc:: ich:: { StableHashingContext , StableHashingContextProvider } ;
44use rustc:: mir;
55use rustc:: mir:: interpret:: {
6- AllocId , Pointer , Scalar , ScalarMaybeUndef , Relocations , Allocation , UndefMask
6+ AllocId , Pointer , Scalar , ScalarMaybeUndef ,
7+ Relocations , Allocation , UndefMask ,
8+ EvalResult , EvalErrorKind ,
79} ;
810
9- use rustc:: ty;
11+ use rustc:: ty:: { self , TyCtxt } ;
1012use rustc:: ty:: layout:: Align ;
13+ use rustc_data_structures:: fx:: FxHashSet ;
1114use rustc_data_structures:: indexed_vec:: IndexVec ;
1215use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher , StableHasherResult } ;
1316use syntax:: ast:: Mutability ;
@@ -16,6 +19,72 @@ use syntax::source_map::Span;
1619use super :: eval_context:: { LocalValue , StackPopCleanup } ;
1720use super :: { Frame , Memory , Machine , Operand , MemPlace , Place , Value } ;
1821
22+ pub ( super ) struct InfiniteLoopDetector < ' a , ' mir , ' tcx : ' a + ' mir , M : Machine < ' mir , ' tcx > > {
23+ /// The set of all `EvalSnapshot` *hashes* observed by this detector.
24+ ///
25+ /// When a collision occurs in this table, we store the full snapshot in
26+ /// `snapshots`.
27+ hashes : FxHashSet < u64 > ,
28+
29+ /// The set of all `EvalSnapshot`s observed by this detector.
30+ ///
31+ /// An `EvalSnapshot` will only be fully cloned once it has caused a
32+ /// collision in `hashes`. As a result, the detector must observe at least
33+ /// *two* full cycles of an infinite loop before it triggers.
34+ snapshots : FxHashSet < EvalSnapshot < ' a , ' mir , ' tcx , M > > ,
35+ }
36+
37+ impl < ' a , ' mir , ' tcx , M > Default for InfiniteLoopDetector < ' a , ' mir , ' tcx , M >
38+ where M : Machine < ' mir , ' tcx > ,
39+ ' tcx : ' a + ' mir ,
40+ {
41+ fn default ( ) -> Self {
42+ InfiniteLoopDetector {
43+ hashes : FxHashSet :: default ( ) ,
44+ snapshots : FxHashSet :: default ( ) ,
45+ }
46+ }
47+ }
48+
49+ impl < ' a , ' mir , ' tcx , M > InfiniteLoopDetector < ' a , ' mir , ' tcx , M >
50+ where M : Machine < ' mir , ' tcx > ,
51+ ' tcx : ' a + ' mir ,
52+ {
53+ /// Returns `true` if the loop detector has not yet observed a snapshot.
54+ pub fn is_empty ( & self ) -> bool {
55+ self . hashes . is_empty ( )
56+ }
57+
58+ pub fn observe_and_analyze (
59+ & mut self ,
60+ tcx : & TyCtxt < ' b , ' tcx , ' tcx > ,
61+ machine : & M ,
62+ memory : & Memory < ' a , ' mir , ' tcx , M > ,
63+ stack : & [ Frame < ' mir , ' tcx > ] ,
64+ ) -> EvalResult < ' tcx , ( ) > {
65+
66+ let mut hcx = tcx. get_stable_hashing_context ( ) ;
67+ let mut hasher = StableHasher :: < u64 > :: new ( ) ;
68+ ( machine, stack) . hash_stable ( & mut hcx, & mut hasher) ;
69+ let hash = hasher. finish ( ) ;
70+
71+ if self . hashes . insert ( hash) {
72+ // No collision
73+ return Ok ( ( ) )
74+ }
75+
76+ info ! ( "snapshotting the state of the interpreter" ) ;
77+
78+ if self . snapshots . insert ( EvalSnapshot :: new ( machine, memory, stack) ) {
79+ // Spurious collision or first cycle
80+ return Ok ( ( ) )
81+ }
82+
83+ // Second cycle
84+ Err ( EvalErrorKind :: InfiniteLoop . into ( ) )
85+ }
86+ }
87+
1988trait SnapshotContext < ' a > {
2089 fn resolve ( & ' a self , id : & AllocId ) -> Option < & ' a Allocation > ;
2190}
@@ -269,7 +338,7 @@ impl<'a, 'b, 'mir, 'tcx, M> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, M>
269338}
270339
271340/// The virtual machine state during const-evaluation at a given point in time.
272- pub struct EvalSnapshot < ' a , ' mir , ' tcx : ' a + ' mir , M : Machine < ' mir , ' tcx > > {
341+ struct EvalSnapshot < ' a , ' mir , ' tcx : ' a + ' mir , M : Machine < ' mir , ' tcx > > {
273342 machine : M ,
274343 memory : Memory < ' a , ' mir , ' tcx , M > ,
275344 stack : Vec < Frame < ' mir , ' tcx > > ,
@@ -278,7 +347,7 @@ pub struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
278347impl < ' a , ' mir , ' tcx , M > EvalSnapshot < ' a , ' mir , ' tcx , M >
279348 where M : Machine < ' mir , ' tcx > ,
280349{
281- pub fn new (
350+ fn new (
282351 machine : & M ,
283352 memory : & Memory < ' a , ' mir , ' tcx , M > ,
284353 stack : & [ Frame < ' mir , ' tcx > ] ) -> Self {
0 commit comments