@@ -3,11 +3,14 @@ use std::hash::{Hash, Hasher};
3
3
use rustc:: ich:: { StableHashingContext , StableHashingContextProvider } ;
4
4
use rustc:: mir;
5
5
use rustc:: mir:: interpret:: {
6
- AllocId , Pointer , Scalar , ScalarMaybeUndef , Relocations , Allocation , UndefMask
6
+ AllocId , Pointer , Scalar , ScalarMaybeUndef ,
7
+ Relocations , Allocation , UndefMask ,
8
+ EvalResult , EvalErrorKind ,
7
9
} ;
8
10
9
- use rustc:: ty;
11
+ use rustc:: ty:: { self , TyCtxt } ;
10
12
use rustc:: ty:: layout:: Align ;
13
+ use rustc_data_structures:: fx:: FxHashSet ;
11
14
use rustc_data_structures:: indexed_vec:: IndexVec ;
12
15
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher , StableHasherResult } ;
13
16
use syntax:: ast:: Mutability ;
@@ -16,6 +19,72 @@ use syntax::source_map::Span;
16
19
use super :: eval_context:: { LocalValue , StackPopCleanup } ;
17
20
use super :: { Frame , Memory , Machine , Operand , MemPlace , Place , Value } ;
18
21
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
+
19
88
trait SnapshotContext < ' a > {
20
89
fn resolve ( & ' a self , id : & AllocId ) -> Option < & ' a Allocation > ;
21
90
}
@@ -269,7 +338,7 @@ impl<'a, 'b, 'mir, 'tcx, M> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, M>
269
338
}
270
339
271
340
/// 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 > > {
273
342
machine : M ,
274
343
memory : Memory < ' a , ' mir , ' tcx , M > ,
275
344
stack : Vec < Frame < ' mir , ' tcx > > ,
@@ -278,7 +347,7 @@ pub struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
278
347
impl < ' a , ' mir , ' tcx , M > EvalSnapshot < ' a , ' mir , ' tcx , M >
279
348
where M : Machine < ' mir , ' tcx > ,
280
349
{
281
- pub fn new (
350
+ fn new (
282
351
machine : & M ,
283
352
memory : & Memory < ' a , ' mir , ' tcx , M > ,
284
353
stack : & [ Frame < ' mir , ' tcx > ] ) -> Self {
0 commit comments