From 9f379ef6dffba1178cba5155d1afb4c5d87110ff Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Sat, 3 Sep 2022 16:00:36 +0300 Subject: fix(tvix/eval): hold thunk borrow as shortly as possible 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 Tested-by: BuildkiteCI --- tvix/eval/src/value/thunk.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'tvix') 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) -> 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; } } } -- cgit 1.4.1