Merge branch 'miri-leak' into events-2
This commit is contained in:
commit
57dd56c8a4
5 files changed
+62
-20
No files matched your search
@@ -86,8 +86,7 @@ jobs:
|
|||||||
|
|
||||||
# working-directory: tokio
|
# working-directory: tokio
|
||||||
env:
|
env:
|
||||||
# todo: disable memory leaks ignore
|
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-retag-fields
|
||||||
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-retag-fields -Zmiri-ignore-leaks
|
|
||||||
PROPTEST_CASES: 10
|
PROPTEST_CASES: 10
|
||||||
|
|
||||||
# Cache the global cargo directory, but NOT the local `target` directory which
|
# Cache the global cargo directory, but NOT the local `target` directory which
|
||||||
|
|||||||
@@ -164,17 +164,11 @@ impl VirtualDom {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Now that all the references are gone, we can safely drop our own references in our listeners.
|
// Now that all the references are gone, we can safely drop our own references in our listeners.
|
||||||
let mut listeners = scope.attributes_to_drop.borrow_mut();
|
let mut listeners = scope.attributes_to_drop_before_render.borrow_mut();
|
||||||
listeners.drain(..).for_each(|listener| {
|
listeners.drain(..).for_each(|listener| {
|
||||||
let listener = unsafe { &*listener };
|
let listener = unsafe { &*listener };
|
||||||
match &listener.value {
|
if let AttributeValue::Listener(l) = &listener.value {
|
||||||
AttributeValue::Listener(l) => {
|
_ = l.take();
|
||||||
_ = l.take();
|
|
||||||
}
|
|
||||||
AttributeValue::Any(a) => {
|
|
||||||
_ = a.take();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
use crate::nodes::RenderReturn;
|
use crate::nodes::RenderReturn;
|
||||||
|
use crate::{Attribute, AttributeValue, VComponent};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::{Cell, UnsafeCell};
|
||||||
|
|
||||||
pub(crate) struct BumpFrame {
|
pub(crate) struct BumpFrame {
|
||||||
pub bump: UnsafeCell<Bump>,
|
pub bump: UnsafeCell<Bump>,
|
||||||
pub node: Cell<*const RenderReturn<'static>>,
|
pub node: Cell<*const RenderReturn<'static>>,
|
||||||
|
|
||||||
|
// The bump allocator will not call the destructor of the objects it allocated. Attributes and props need to have there destructor called, so we keep a list of them to drop before the bump allocator is reset.
|
||||||
|
pub(crate) attributes_to_drop_before_reset: RefCell<Vec<*const Attribute<'static>>>,
|
||||||
|
pub(crate) props_to_drop_before_reset: RefCell<Vec<*const VComponent<'static>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BumpFrame {
|
impl BumpFrame {
|
||||||
@@ -13,6 +19,8 @@ impl BumpFrame {
|
|||||||
Self {
|
Self {
|
||||||
bump: UnsafeCell::new(bump),
|
bump: UnsafeCell::new(bump),
|
||||||
node: Cell::new(std::ptr::null()),
|
node: Cell::new(std::ptr::null()),
|
||||||
|
attributes_to_drop_before_reset: Default::default(),
|
||||||
|
props_to_drop_before_reset: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,8 +39,38 @@ impl BumpFrame {
|
|||||||
unsafe { &*self.bump.get() }
|
unsafe { &*self.bump.get() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::mut_from_ref)]
|
pub(crate) fn add_attribute_to_drop(&self, attribute: *const Attribute<'static>) {
|
||||||
pub(crate) unsafe fn bump_mut(&self) -> &mut Bump {
|
self.attributes_to_drop_before_reset
|
||||||
unsafe { &mut *self.bump.get() }
|
.borrow_mut()
|
||||||
|
.push(attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset the bump allocator and drop all the attributes and props that were allocated in it.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The caller must insure that no reference to anything allocated in the bump allocator is available after this function is called.
|
||||||
|
pub(crate) unsafe fn reset(&self) {
|
||||||
|
let mut attributes = self.attributes_to_drop_before_reset.borrow_mut();
|
||||||
|
attributes.drain(..).for_each(|attribute| {
|
||||||
|
let attribute = unsafe { &*attribute };
|
||||||
|
if let AttributeValue::Any(l) = &attribute.value {
|
||||||
|
_ = l.take();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let mut props = self.props_to_drop_before_reset.borrow_mut();
|
||||||
|
props.drain(..).for_each(|prop| {
|
||||||
|
let prop = unsafe { &*prop };
|
||||||
|
_ = prop.props.borrow_mut().take();
|
||||||
|
});
|
||||||
|
unsafe {
|
||||||
|
let bump = &mut *self.bump.get();
|
||||||
|
bump.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for BumpFrame {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.reset() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ impl VirtualDom {
|
|||||||
hook_idx: Default::default(),
|
hook_idx: Default::default(),
|
||||||
|
|
||||||
borrowed_props: Default::default(),
|
borrowed_props: Default::default(),
|
||||||
attributes_to_drop: Default::default(),
|
attributes_to_drop_before_render: Default::default(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let context =
|
let context =
|
||||||
@@ -54,7 +54,7 @@ impl VirtualDom {
|
|||||||
|
|
||||||
let new_nodes = unsafe {
|
let new_nodes = unsafe {
|
||||||
let scope = &self.scopes[scope_id.0];
|
let scope = &self.scopes[scope_id.0];
|
||||||
scope.previous_frame().bump_mut().reset();
|
scope.previous_frame().reset();
|
||||||
|
|
||||||
scope.context().suspended.set(false);
|
scope.context().suspended.set(false);
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ pub struct ScopeState {
|
|||||||
pub(crate) hook_idx: Cell<usize>,
|
pub(crate) hook_idx: Cell<usize>,
|
||||||
|
|
||||||
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
|
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
|
||||||
pub(crate) attributes_to_drop: RefCell<Vec<*const Attribute<'static>>>,
|
pub(crate) attributes_to_drop_before_render: RefCell<Vec<*const Attribute<'static>>>,
|
||||||
|
|
||||||
pub(crate) props: Option<Box<dyn AnyProps<'static>>>,
|
pub(crate) props: Option<Box<dyn AnyProps<'static>>>,
|
||||||
}
|
}
|
||||||
@@ -348,25 +348,36 @@ impl<'src> ScopeState {
|
|||||||
pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
|
pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
|
||||||
let element = rsx.call(self);
|
let element = rsx.call(self);
|
||||||
|
|
||||||
let mut listeners = self.attributes_to_drop.borrow_mut();
|
let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
|
||||||
for attr in element.dynamic_attrs {
|
for attr in element.dynamic_attrs {
|
||||||
match attr.value {
|
match attr.value {
|
||||||
AttributeValue::Any(_) | AttributeValue::Listener(_) => {
|
// We need to drop listeners before the next render because they may borrow data from the borrowed props which will be dropped
|
||||||
|
AttributeValue::Listener(_) => {
|
||||||
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
||||||
listeners.push(unbounded);
|
listeners.push(unbounded);
|
||||||
}
|
}
|
||||||
|
// We need to drop any values manually to make sure that their drop implementation is called before the next render
|
||||||
|
AttributeValue::Any(_) => {
|
||||||
|
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
||||||
|
self.previous_frame().add_attribute_to_drop(unbounded);
|
||||||
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut props = self.borrowed_props.borrow_mut();
|
let mut props = self.borrowed_props.borrow_mut();
|
||||||
|
let mut drop_props = self
|
||||||
|
.previous_frame()
|
||||||
|
.props_to_drop_before_reset
|
||||||
|
.borrow_mut();
|
||||||
for node in element.dynamic_nodes {
|
for node in element.dynamic_nodes {
|
||||||
if let DynamicNode::Component(comp) = node {
|
if let DynamicNode::Component(comp) = node {
|
||||||
|
let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) };
|
||||||
if !comp.static_props {
|
if !comp.static_props {
|
||||||
let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) };
|
|
||||||
props.push(unbounded);
|
props.push(unbounded);
|
||||||
}
|
}
|
||||||
|
drop_props.push(unbounded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user