about summary refs log tree commit diff
path: root/tvix/eval
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-09-03T13·00+0300
committertazjin <tazjin@tvl.su>2022-09-08T20·17+0000
commit9f379ef6dffba1178cba5155d1afb4c5d87110ff (patch)
tree0fda233dbb0764320f98ac9638f97a5ebdd92f2b /tvix/eval
parent48d5f4fd573e05410a3b0dfc3bb2a0289e8736b1 (diff)
fix(tvix/eval): hold thunk borrow as shortly as possible r/4769
At the point where control flow exits Thunk::force (which may be due
to recursing), it is vital that there is no longer a borrow to the
inner thunk representation, otherwise this can cause accidental
infinite recursion (which will be detected, but cause failures on
valid code).

Change-Id: I2846f3142830ae3110a4f5d2299e9d7928634504
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6436
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval')
-rw-r--r--tvix/eval/src/value/thunk.rs13
1 files changed, 6 insertions, 7 deletions
diff --git a/tvix/eval/src/value/thunk.rs b/tvix/eval/src/value/thunk.rs
index e3f7846125f9..ad56b5eaf646 100644
--- a/tvix/eval/src/value/thunk.rs
+++ b/tvix/eval/src/value/thunk.rs
@@ -53,7 +53,7 @@ impl Thunk {
     pub fn new(lambda: Rc<Lambda>) -> Self {
         Thunk(Rc::new(RefCell::new(ThunkRepr::Suspended {
             upvalues: Vec::with_capacity(lambda.upvalue_count),
-            lambda,
+            lambda: lambda.clone(),
         })))
     }
 
@@ -65,12 +65,9 @@ impl Thunk {
     /// case of nested thunks, the intermediate thunk representations
     /// are replaced.
     pub fn force(&self, vm: &mut VM) -> Result<(), ErrorKind> {
-        // Due to mutable borrowing rules, the following code can't
-        // easily use a match statement or something like that; it
-        // requires a bit of manual fiddling.
-        let mut thunk_mut = self.0.borrow_mut();
-
         loop {
+            let mut thunk_mut = self.0.borrow_mut();
+
             match *thunk_mut {
                 ThunkRepr::Evaluated(Value::Thunk(ref inner_thunk)) => {
                     let inner_repr = inner_thunk.0.borrow().clone();
@@ -84,10 +81,12 @@ impl Thunk {
                     if let ThunkRepr::Suspended { lambda, upvalues } =
                         std::mem::replace(&mut *thunk_mut, ThunkRepr::Blackhole)
                     {
-                        *thunk_mut = ThunkRepr::Evaluated(
+                        drop(thunk_mut);
+                        let evaluated = ThunkRepr::Evaluated(
                             vm.call(lambda, upvalues, 0)
                                 .map_err(|e| ErrorKind::ThunkForce(Box::new(e)))?,
                         );
+                        (*self.0.borrow_mut()) = evaluated;
                     }
                 }
             }