diff --git a/third_party/move/move-vm/types/src/values/values_impl.rs b/third_party/move/move-vm/types/src/values/values_impl.rs index 4a6a982970e..f1aefbf2020 100644 --- a/third_party/move/move-vm/types/src/values/values_impl.rs +++ b/third_party/move/move-vm/types/src/values/values_impl.rs @@ -37,7 +37,7 @@ use std::{ cell::RefCell, cmp::Ordering, fmt::{self, Debug, Display, Formatter}, - iter, mem, + iter, mem::{self, ManuallyDrop}, rc::Rc, }; use triomphe::Arc as TriompheArc; @@ -119,6 +119,51 @@ pub enum Value { ClosureValue(Closure), } +#[derive(Debug)] +pub(crate) struct Values(Rc>>); + +impl Values { + #[allow(unsafe_code)] + fn unwrap(self) -> Rc>> { + let this = ManuallyDrop::new(self); + unsafe { std::ptr::read(&this.0) } + } +} + +impl std::ops::Deref for Values { + type Target = Rc>>; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Drop for Values { + fn drop(&mut self) { + fn visit(vs: &mut Values) -> Vec { + if let Some(ref_cell) = Rc::get_mut(&mut vs.0) { + std::mem::take(ref_cell.get_mut()) + } else { + vec![] + } + } + + let mut to_visit = visit(self); + while let Some(v) = to_visit.pop() { + let Value::Container(c) = v else { + continue; + }; + match c { + Container::Locals(mut vs) | Container::Vec(mut vs) | Container::Struct(mut vs) => { + to_visit.append(&mut visit(&mut vs)); + }, + _ => {} + } + } + } +} + /// A container is a collection of values. It is used to represent data structures like a /// Move vector or struct. /// @@ -130,9 +175,9 @@ pub enum Value { /// making it possible to be shared by references. #[derive(Debug)] pub(crate) enum Container { - Locals(Rc>>), - Vec(Rc>>), - Struct(Rc>>), + Locals(Values), + Vec(Values), + Struct(Values), VecU8(Rc>>), VecU64(Rc>>), VecU128(Rc>>), @@ -405,10 +450,10 @@ impl Container { } fn master_signer(x: AccountAddress) -> Self { - Container::Struct(Rc::new(RefCell::new(vec![ + Container::Struct(Values(Rc::new(RefCell::new(vec![ Value::U16(MASTER_SIGNER_VARIANT), Value::Address(Box::new(x)), - ]))) + ])))) } } @@ -608,8 +653,8 @@ impl Container { } Ok(match self { - Self::Vec(r) => Self::Vec(copy_rc_ref_vec_val(r, depth, max_depth)?), - Self::Struct(r) => Self::Struct(copy_rc_ref_vec_val(r, depth, max_depth)?), + Self::Vec(r) => Self::Vec(Values(copy_rc_ref_vec_val(r, depth, max_depth)?)), + Self::Struct(r) => Self::Struct(Values(copy_rc_ref_vec_val(r, depth, max_depth)?)), Self::VecU8(r) => Self::VecU8(Rc::new(RefCell::new(r.borrow().clone()))), Self::VecU16(r) => Self::VecU16(Rc::new(RefCell::new(r.borrow().clone()))), @@ -638,8 +683,8 @@ impl Container { // Note(inline): expensive to inline, +10s compile time fn copy_by_ref(&self) -> Self { match self { - Self::Vec(r) => Self::Vec(Rc::clone(r)), - Self::Struct(r) => Self::Struct(Rc::clone(r)), + Self::Vec(r) => Self::Vec(Values(Rc::clone(&r.0))), + Self::Struct(r) => Self::Struct(Values(Rc::clone(&r.0))), Self::VecU8(r) => Self::VecU8(Rc::clone(r)), Self::VecU16(r) => Self::VecU16(Rc::clone(r)), @@ -656,7 +701,7 @@ impl Container { Self::VecBool(r) => Self::VecBool(Rc::clone(r)), Self::VecAddress(r) => Self::VecAddress(Rc::clone(r)), - Self::Locals(r) => Self::Locals(Rc::clone(r)), + Self::Locals(r) => Self::Locals(Values(Rc::clone(&r.0))), } } } @@ -1504,9 +1549,27 @@ impl ContainerRef { }}; } + macro_rules! assign_values { + ($r1:expr, $tc:ident) => {{ + let r = match c { + Container::$tc(v) => v.unwrap(), + _ => { + return Err(PartialVMError::new( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + ) + .with_message( + "failed to write_ref: container type mismatch".to_string(), + ) + .with_sub_status(move_core_types::vm_status::sub_status::unknown_invariant_violation::EPARANOID_FAILURE)) + }, + }; + *$r1.borrow_mut() = take_unique_ownership(r)?; + }}; + } + match self.container() { - Container::Struct(r) => assign!(r, Struct), - Container::Vec(r) => assign!(r, Vec), + Container::Struct(r) => assign_values!(r, Struct), + Container::Vec(r) => assign_values!(r, Vec), Container::VecU8(r) => assign!(r, VecU8), Container::VecU16(r) => assign!(r, VecU16), Container::VecU32(r) => assign!(r, VecU32), @@ -2135,7 +2198,7 @@ impl Locals { | Value::ClosureValue(_) | Value::DelayedFieldID { .. } => Ok(Value::IndexedRef(IndexedRef { idx, - container_ref: ContainerRef::Local(Container::Locals(Rc::clone(&self.0))), + container_ref: ContainerRef::Local(Container::Locals(Values(Rc::clone(&self.0)))), })), Value::ContainerRef(_) | Value::Invalid | Value::IndexedRef(_) => Err( @@ -2379,7 +2442,7 @@ impl Value { #[cfg_attr(feature = "force-inline", inline(always))] pub fn struct_(s: Struct) -> Self { - Value::Container(Container::Struct(Rc::new(RefCell::new(s.fields)))) + Value::Container(Container::Struct(Values(Rc::new(RefCell::new(s.fields))))) } #[cfg_attr(feature = "force-inline", inline(always))] @@ -2494,9 +2557,9 @@ impl Value { Ok(v) }) .collect::>>()?; - Ok(Self::Container(Container::Vec(Rc::new(RefCell::new( + Ok(Self::Container(Container::Vec(Values(Rc::new(RefCell::new( values, - ))))) + )))))) } pub fn closure( @@ -2635,7 +2698,7 @@ impl VMValueCast for Value { fn cast(self) -> PartialVMResult { match self { Value::Container(Container::Struct(r)) => Ok(Struct { - fields: take_unique_ownership(r)?, + fields: take_unique_ownership(r.unwrap())?, }), v => Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR) .with_message(format!("cannot cast {:?} to struct", v,))), @@ -2677,7 +2740,7 @@ impl VMValueCast> for Value { fn cast(self) -> PartialVMResult> { match self { Value::Container(Container::Vec(c)) => { - Ok(take_unique_ownership(c)?.into_iter().collect()) + Ok(take_unique_ownership(c.unwrap())?.into_iter().collect()) }, Value::Address(_) | Value::Bool(_) @@ -3919,7 +3982,7 @@ impl Vector { | Type::Struct { .. } | Type::StructInstantiation { .. } | Type::Function { .. } => { - Value::Container(Container::Vec(Rc::new(RefCell::new(elements)))) + Value::Container(Container::Vec(Values(Rc::new(RefCell::new(elements))))) }, Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { @@ -3991,7 +4054,7 @@ impl Vector { .into_iter() .map(Value::address) .collect(), - Container::Vec(r) => take_unique_ownership(r)?.into_iter().collect(), + Container::Vec(r) => take_unique_ownership(r.unwrap())?.into_iter().collect(), Container::Locals(_) | Container::Struct(_) => { return Err(PartialVMError::new_invariant_violation( "Unexpected non-vector container", @@ -4178,13 +4241,13 @@ impl GlobalValueImpl { Self::Fresh { value } => { let fields = Self::expect_struct_fields(value); Ok(Value::ContainerRef(ContainerRef::Local(Container::Struct( - Rc::clone(fields), + Values(Rc::clone(fields)), )))) }, Self::Cached { value, status } => { let fields = Self::expect_struct_fields(value); Ok(Value::ContainerRef(ContainerRef::Global { - container: Container::Struct(Rc::clone(fields)), + container: Container::Struct(Values(Rc::clone(fields))), status: Rc::clone(status), })) }, @@ -5024,7 +5087,7 @@ impl<'d> serde::de::DeserializeSeed<'d> for DeserializationSeed<'_, &MoveTypeLay layout, }; let vector = deserializer.deserialize_seq(VectorElementVisitor(seed))?; - Value::Container(Container::Vec(Rc::new(RefCell::new(vector)))) + Value::Container(Container::Vec(Values(Rc::new(RefCell::new(vector))))) }, }), @@ -5767,7 +5830,9 @@ pub mod prop { }) .boxed(), layout => vec(value_strategy_with_layout(layout), 0..10) - .prop_map(|vals| Value::Container(Container::Vec(Rc::new(RefCell::new(vals))))) + .prop_map(|vals| { + Value::Container(Container::Vec(Values(Rc::new(RefCell::new(vals))))) + }) .boxed(), }, L::Struct(_struct_layout @ MoveStructLayout::RuntimeVariants(variants)) => {