Mercurial > hg
changeset 42850:8f549c46bc64
rust-cpython: pair leaked reference with its manager object
Still leak_immutable() is unsafe since leak_handle must live longer than
the leaked_ref.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 01 Sep 2019 17:48:24 +0900 |
parents | 8db8fa1de2ef |
children | 64e28b891796 |
files | rust/hg-cpython/src/dirstate/dirs_multiset.rs rust/hg-cpython/src/dirstate/dirstate_map.rs rust/hg-cpython/src/ref_sharing.rs |
diffstat | 3 files changed, 33 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs Sun Sep 01 17:37:30 2019 +0900 +++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs Sun Sep 01 17:48:24 2019 +0900 @@ -86,10 +86,11 @@ }) } def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> { + let (leak_handle, leaked_ref) = self.leak_immutable(py)?; DirsMultisetKeysIterator::create_instance( py, - RefCell::new(Some(DirsMultisetLeakedRef::new(py, &self))), - RefCell::new(Box::new(self.leak_immutable(py)?.iter())), + RefCell::new(Some(leak_handle)), + RefCell::new(Box::new(leaked_ref.iter())), ) }
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs Sun Sep 01 17:37:30 2019 +0900 +++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs Sun Sep 01 17:48:24 2019 +0900 @@ -319,26 +319,29 @@ } def keys(&self) -> PyResult<DirstateMapKeysIterator> { + let (leak_handle, leaked_ref) = self.leak_immutable(py)?; DirstateMapKeysIterator::from_inner( py, - Some(DirstateMapLeakedRef::new(py, &self)), - Box::new(self.leak_immutable(py)?.iter()), + Some(leak_handle), + Box::new(leaked_ref.iter()), ) } def items(&self) -> PyResult<DirstateMapItemsIterator> { + let (leak_handle, leaked_ref) = self.leak_immutable(py)?; DirstateMapItemsIterator::from_inner( py, - Some(DirstateMapLeakedRef::new(py, &self)), - Box::new(self.leak_immutable(py)?.iter()), + Some(leak_handle), + Box::new(leaked_ref.iter()), ) } def __iter__(&self) -> PyResult<DirstateMapKeysIterator> { + let (leak_handle, leaked_ref) = self.leak_immutable(py)?; DirstateMapKeysIterator::from_inner( py, - Some(DirstateMapLeakedRef::new(py, &self)), - Box::new(self.leak_immutable(py)?.iter()), + Some(leak_handle), + Box::new(leaked_ref.iter()), ) } @@ -431,18 +434,20 @@ } def copymapiter(&self) -> PyResult<CopyMapKeysIterator> { + let (leak_handle, leaked_ref) = self.leak_immutable(py)?; CopyMapKeysIterator::from_inner( py, - Some(DirstateMapLeakedRef::new(py, &self)), - Box::new(self.leak_immutable(py)?.copy_map.iter()), + Some(leak_handle), + Box::new(leaked_ref.copy_map.iter()), ) } def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> { + let (leak_handle, leaked_ref) = self.leak_immutable(py)?; CopyMapItemsIterator::from_inner( py, - Some(DirstateMapLeakedRef::new(py, &self)), - Box::new(self.leak_immutable(py)?.copy_map.iter()), + Some(leak_handle), + Box::new(leaked_ref.copy_map.iter()), ) }
--- a/rust/hg-cpython/src/ref_sharing.rs Sun Sep 01 17:37:30 2019 +0900 +++ b/rust/hg-cpython/src/ref_sharing.rs Sun Sep 01 17:48:24 2019 +0900 @@ -216,14 +216,24 @@ .borrow_mut(py, unsafe { data.borrow_mut() }) } + /// Returns a leaked reference and its management object. + /// + /// # Safety + /// + /// It's up to you to make sure that the management object lives + /// longer than the leaked reference. Otherwise, you'll get a + /// dangling reference. fn leak_immutable<'a>( &'a self, py: Python<'a>, - ) -> PyResult<&'static $inner_struct> { + ) -> PyResult<($leaked, &'static $inner_struct)> { // assert $data_member type use crate::ref_sharing::PySharedRefCell; let data: &PySharedRefCell<_> = self.$data_member(py); - self.py_shared_state(py).leak_immutable(py, data) + let static_ref = + self.py_shared_state(py).leak_immutable(py, data)?; + let leak_handle = $leaked::new(py, self); + Ok((leak_handle, static_ref)) } } @@ -336,10 +346,11 @@ /// data py_shared_state: PySharedState; /// /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> { +/// let (leak_handle, leaked_ref) = self.leak_immutable(py)?; /// MyTypeItemsIterator::create_instance( /// py, -/// RefCell::new(Some(MyTypeLeakedRef::new(py, &self))), -/// RefCell::new(self.leak_immutable(py).iter()), +/// RefCell::new(Some(leak_handle)), +/// RefCell::new(leaked_ref.iter()), /// ) /// } /// });