From ccba2fb73ed9062f49b26b4ba466a1d7bfad0db8 Mon Sep 17 00:00:00 2001 From: Andrey Goncharov Date: Fri, 10 Mar 2023 08:33:19 -0800 Subject: [PATCH] Prevent stack overflow in cyclical graphs Summary: Logview reported "Error: Maximum call stack size exceeded" for "getElementLeaves". Apparently, there was a cycle in the graph that caused it. The new implementation should ignore cycles. Reviewed By: lblasa Differential Revision: D43976359 fbshipit-source-id: bb5218a3b29706146501241492ee079773d5abc3 --- desktop/plugins/public/layout/Inspector.tsx | 37 +++++++++++++-------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/desktop/plugins/public/layout/Inspector.tsx b/desktop/plugins/public/layout/Inspector.tsx index 06684aa75..cb3d0f0bf 100644 --- a/desktop/plugins/public/layout/Inspector.tsx +++ b/desktop/plugins/public/layout/Inspector.tsx @@ -341,20 +341,29 @@ export default class Inspector extends Component { } getElementLeaves(tree: ElementSelectorNode): Array { - return tree - ? Object.entries(tree).reduce( - ( - currLeafNode: Array, - [id, children]: [ElementID, ElementSelectorNode], - ): Array => - currLeafNode.concat( - Object.keys(children).length > 0 - ? this.getElementLeaves(children) - : [id], - ), - [], - ) - : []; + if (!tree) { + return []; + } + const leavesSet = new Set(); + + const treeIteratorStack: [ElementID, ElementSelectorNode][] = [ + ...Object.entries(tree), + ]; + while (treeIteratorStack.length) { + const [id, children] = treeIteratorStack.pop()!; + + if (leavesSet.has(id)) { + continue; + } + + if (Object.keys(children).length) { + treeIteratorStack.push(...Object.entries(children)); + } else { + leavesSet.add(id); + } + } + + return [...leavesSet]; } /// Return path from given tree structure and id if id is not null; otherwise return any path