From f7ccfcfff69ce1789132874c8669e3bdda815ae3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 9 Jun 2026 13:06:59 +0200 Subject: [PATCH] #14182 Fix stack overflow when destroying deep AABB bounding box trees The bounding box tree is destroyed by deleteInternalNodesBottomUp, which recursed once per tree level. For deep or unbalanced trees this overflowed the call stack during project close (RigMainGrid destruction). Replace the recursion with an explicit stack. Deleting an internal node does not touch its children, so the child pointers are read before the node is deleted and the deletion order is irrelevant. Leaf nodes remain pooled and are not deleted individually. --- Fwk/VizFwk/LibGeometry/cvfBoundingBoxTree.cpp | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Fwk/VizFwk/LibGeometry/cvfBoundingBoxTree.cpp b/Fwk/VizFwk/LibGeometry/cvfBoundingBoxTree.cpp index d38c9c83d8..9bee5e5bcd 100644 --- a/Fwk/VizFwk/LibGeometry/cvfBoundingBoxTree.cpp +++ b/Fwk/VizFwk/LibGeometry/cvfBoundingBoxTree.cpp @@ -793,15 +793,29 @@ cvf::AABBTreeNodeLeaf* AABBTree::createOrAssignLeaf(size_t leafIndex, const std: void AABBTree::deleteInternalNodesBottomUp(AABBTreeNode* node) { // All leaf nodes (AABBTreeNodeLeaf) are allocated in m_leafPool and does not require a delete - if (node->type() == AB_LEAF) return; + if (!node || node->type() == AB_LEAF) return; - auto internalNode = dynamic_cast(node); - CVF_ASSERT(internalNode); + // Use an explicit stack instead of recursion. The tree can become very unbalanced (height + // proportional to the leaf count rather than log2 of it), and recursing once per level would + // overflow the call stack when the tree is destroyed. Deleting an internal node does not touch + // its children, so the children pointers are read before the node is deleted and the order in + // which the internal nodes are deleted does not matter. + std::vector pendingNodes; + pendingNodes.push_back(static_cast(node)); - AABBTree::deleteInternalNodesBottomUp(internalNode->left()); - AABBTree::deleteInternalNodesBottomUp(internalNode->right()); + while (!pendingNodes.empty()) + { + AABBTreeNodeInternal* internalNode = pendingNodes.back(); + pendingNodes.pop_back(); - delete internalNode; + AABBTreeNode* left = internalNode->left(); + AABBTreeNode* right = internalNode->right(); + + if (left && left->type() == AB_INTERNAL) pendingNodes.push_back(static_cast(left)); + if (right && right->type() == AB_INTERNAL) pendingNodes.push_back(static_cast(right)); + + delete internalNode; + } } //--------------------------------------------------------------------------------------------------