From a3cdbfe87f5a8daef11a154ef3edb5a3a5c12f77 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 27 Aug 2024 12:27:55 +0200 Subject: [PATCH] fix(core): avoid leaking memory if component throws during creation (#57546) When we create the LView for a component, we track it in the `TRACKED_LVIEWS` map. It gets untracked when it is destroy, but if it throws during creation, the user won't have access to a `ComponentRef` in order to clean it up. These changes automatically untrack the related LViews if the component couldn't be created. PR Close #57546 --- packages/core/src/render3/component_ref.ts | 12 +++++++++++- .../animations-standalone/bundle.golden_symbols.json | 3 +++ .../bundling/animations/bundle.golden_symbols.json | 3 +++ .../cyclic_import/bundle.golden_symbols.json | 3 +++ .../test/bundling/defer/bundle.golden_symbols.json | 3 +++ .../forms_reactive/bundle.golden_symbols.json | 3 +++ .../forms_template_driven/bundle.golden_symbols.json | 3 +++ .../bundling/hello_world/bundle.golden_symbols.json | 3 +++ .../bundling/hydration/bundle.golden_symbols.json | 3 +++ .../test/bundling/router/bundle.golden_symbols.json | 3 +++ .../standalone_bootstrap/bundle.golden_symbols.json | 3 +++ .../test/bundling/todo/bundle.golden_symbols.json | 3 +++ 12 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 01b07325f1b..6b3810e7459 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -88,6 +88,7 @@ import {debugStringifyTypeForError, stringifyForError} from './util/stringify_ut import {getComponentLViewByIndex, getNativeByTNode, getTNode} from './util/view_utils'; import {ViewRef} from './view_ref'; import {ChainedInjector} from './chained_injector'; +import {unregisterLView} from './interfaces/lview_tracking'; export class ComponentFactoryResolver extends AbstractComponentFactoryResolver { /** @@ -333,6 +334,7 @@ export class ComponentFactory extends AbstractComponentFactory { let component: T; let tElementNode: TElementNode; + let componentView: LView | null = null; try { const rootComponentDef = this.componentDef; @@ -354,7 +356,7 @@ export class ComponentFactory extends AbstractComponentFactory { } const hostTNode = createRootComponentTNode(rootLView, hostRNode); - const componentView = createRootComponentView( + componentView = createRootComponentView( hostTNode, hostRNode, rootComponentDef, @@ -388,6 +390,14 @@ export class ComponentFactory extends AbstractComponentFactory { [LifecycleHooksFeature], ); renderView(rootTView, rootLView, null); + } catch (e) { + // Stop tracking the views if creation failed since + // the consumer won't have a way to dereference them. + if (componentView !== null) { + unregisterLView(componentView); + } + unregisterLView(rootLView); + throw e; } finally { leaveView(); } diff --git a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json index f192935f66b..e620d87174b 100644 --- a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json @@ -1478,6 +1478,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/animations/bundle.golden_symbols.json b/packages/core/test/bundling/animations/bundle.golden_symbols.json index e256da77766..8d7c319332c 100644 --- a/packages/core/test/bundling/animations/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations/bundle.golden_symbols.json @@ -1553,6 +1553,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index 607449b33a9..451205243f2 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -1253,6 +1253,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/defer/bundle.golden_symbols.json b/packages/core/test/bundling/defer/bundle.golden_symbols.json index 7fa48434dd8..24cd75b8b3d 100644 --- a/packages/core/test/bundling/defer/bundle.golden_symbols.json +++ b/packages/core/test/bundling/defer/bundle.golden_symbols.json @@ -2498,6 +2498,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index 0c7bd88abaa..aa1136d48c4 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -1889,6 +1889,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "untracked" }, diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index 5daa57762e3..84696708788 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -1871,6 +1871,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "untracked" }, diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index ad2d00432f7..db0006ae1d6 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -995,6 +995,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/hydration/bundle.golden_symbols.json b/packages/core/test/bundling/hydration/bundle.golden_symbols.json index 12ff71ca3e3..cdb158ae439 100644 --- a/packages/core/test/bundling/hydration/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hydration/bundle.golden_symbols.json @@ -1385,6 +1385,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index 7630b62d86e..8f93f77ae82 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -2159,6 +2159,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapElementRef" }, diff --git a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json index d506429b53d..8e871b3a808 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -1103,6 +1103,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 9326bcda812..f062204aafc 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -1505,6 +1505,9 @@ { "name": "uniqueIdCounter" }, + { + "name": "unregisterLView" + }, { "name": "unwrapRNode" },