Fix leak in render macro

This commit is contained in:
Jonathan Kelley committed 2024-01-08 19:20:31 -08:00
1 parent 0a35b5a670
commit 44a27bf8a3
9 files changed
+197 -114

No files matched your search

+75 -47
View File
@@ -2,13 +2,13 @@ use crate::{
any_props::AnyProps,
any_props::VProps,
bump_frame::BumpFrame,
innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText},
innerlude::{DynamicNode, ElementRef, EventHandler, VComponent, VNodeId, VText},
lazynodes::LazyNodes,
nodes::{IntoAttributeValue, IntoDynNode, RenderReturn},
runtime::Runtime,
scope_context::ScopeContext,
AnyValue, Attribute, AttributeType, AttributeValue, Element, Event, MountedAttribute,
Properties, TaskId,
AnyValue, Attribute, AttributeType, AttributeValue, Element, ElementId, Event,
MountedAttribute, Properties, TaskId, Template, VNode,
};
use bumpalo::{boxed::Box as BumpBox, Bump};
use std::{
@@ -348,17 +348,76 @@ impl<'src> ScopeState {
/// }
/// ```
pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
let element = rsx.call(self);
// <<<<<<< HEAD
// let element = rsx.call(self);
// let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
// for attr in element.dynamic_attrs {
// attr.ty.for_each(|attr| {
// match attr.value {
// // 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) };
// 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 drop_props = self
// .previous_frame()
// .props_to_drop_before_reset
// .borrow_mut();
// for node in element.dynamic_nodes {
// if let DynamicNode::Component(comp) = node {
// let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) };
// if !comp.static_props {
// props.push(unbounded);
// }
// drop_props.push(unbounded);
// }
// }
// Some(element)
// =======
// Note: We can't do anything in this function related to safety because the user could always circumvent it by creating a VNode manually and return it without calling this function
Some(rsx.call(self))
// >>>>>>> 9fe172e9 (Fix leak in render macro)
}
/// Create a [`crate::VNode`] from the component parts
pub fn vnode(
&'src self,
parent: Cell<Option<ElementRef>>,
key: Option<&'src str>,
template: Cell<Template<'static>>,
root_ids: RefCell<bumpalo::collections::Vec<'src, ElementId>>,
dynamic_nodes: &'src [DynamicNode<'src>],
dynamic_attrs: &'src [MountedAttribute<'src>],
) -> VNode<'src> {
let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
for attr in element.dynamic_attrs {
attr.ty.for_each(|attr| {
for attr in dynamic_attrs {
let attrs = match attr.ty {
AttributeType::Single(ref attr) => std::slice::from_ref(attr),
AttributeType::Many(attrs) => attrs,
};
for attr in attrs {
match attr.value {
// 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) };
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) };
@@ -367,7 +426,7 @@ impl<'src> ScopeState {
_ => (),
}
})
}
}
let mut props = self.borrowed_props.borrow_mut();
@@ -375,7 +434,7 @@ impl<'src> ScopeState {
.previous_frame()
.props_to_drop_before_reset
.borrow_mut();
for node in element.dynamic_nodes {
for node in dynamic_nodes {
if let DynamicNode::Component(comp) = node {
let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) };
if !comp.static_props {
@@ -385,45 +444,14 @@ impl<'src> ScopeState {
}
}
Some(element)
}
#[doc(hidden)]
/// Take a [`crate::VNode`] and link it to a [`ScopeState`]
///
/// This is used internally in the render macro
pub fn link_node(&'src self, element: &crate::VNode<'src>) {
let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
for attr in element.dynamic_attrs {
match attr.value {
// 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) };
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 drop_props = self
.previous_frame()
.props_to_drop_before_reset
.borrow_mut();
for node in element.dynamic_nodes {
if let DynamicNode::Component(comp) = node {
let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) };
if !comp.static_props {
props.push(unbounded);
}
drop_props.push(unbounded);
}
VNode {
stable_id: Default::default(),
key,
parent,
template,
root_ids,
dynamic_nodes,
dynamic_attrs,
}
}