diff options
author | Vincent Ambo <mail@tazj.in> | 2022-09-03T13·00+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-09-08T20·17+0000 |
commit | 9f379ef6dffba1178cba5155d1afb4c5d87110ff (patch) | |
tree | 0fda233dbb0764320f98ac9638f97a5ebdd92f2b /tvix | |
parent | 48d5f4fd573e05410a3b0dfc3bb2a0289e8736b1 (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')
-rw-r--r-- | tvix/eval/src/value/thunk.rs | 13 |
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; } } } |