From b76a5e22aed9bb889c0bdeb2e32eb485c3b85d9c Mon Sep 17 00:00:00 2001 From: Garux Date: Thu, 30 Oct 2025 17:10:34 +0500 Subject: [PATCH] fix FloodAreas() stack overflow in extreme cases --- tools/quake3/q3map2/portals.cpp | 64 ++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/tools/quake3/q3map2/portals.cpp b/tools/quake3/q3map2/portals.cpp index 3a4eafa2..0fdb554f 100644 --- a/tools/quake3/q3map2/portals.cpp +++ b/tools/quake3/q3map2/portals.cpp @@ -615,37 +615,45 @@ static int c_areas; floods through leaf portals to tag leafs with an area */ -static void FloodAreas_r( node_t *node ){ - if ( node->area != AREA_INVALID ) { - return; - } - if ( node->cluster == CLUSTER_OPAQUE ) { - return; - } +static void FloodAreas( node_t *startNode ){ + std::vector nodes{ startNode }, nodes2; + while( !nodes.empty() ){ + for( node_t *node : nodes ) + { + if ( node->area != AREA_INVALID ) { + continue; + } + if ( node->cluster == CLUSTER_OPAQUE ) { + continue; + } - node->area = c_areas; + node->area = c_areas; - /* ydnar: skybox nodes set the skybox area */ - if ( node->skybox ) { - skyboxArea = c_areas; - } + /* ydnar: skybox nodes set the skybox area */ + if ( node->skybox ) { + skyboxArea = c_areas; + } - for ( const portal_t *p = node->portals; p; p = p->nextPortal( node ) ) - { - /* ydnar: allow areaportal portals to block area flow */ - /* this check alone w/o node->areaportal path seems sufficient - besides when node->compileFlags are overriden by hint or struct split flush with areaportal - we make it persistent in FilterBrushIntoTree_r() - note: node->areaportal way fails for leafs with only opaque and areaportal portals */ - if ( p->compileFlags & C_AREAPORTAL ) { - continue; + for ( const portal_t *p = node->portals; p; p = p->nextPortal( node ) ) + { + /* ydnar: allow areaportal portals to block area flow */ + /* this check alone w/o node->areaportal path seems sufficient + besides when node->compileFlags are overriden by hint or struct split flush with areaportal + we make it persistent in FilterBrushIntoTree_r() + note: node->areaportal way fails for leafs with only opaque and areaportal portals */ + if ( p->compileFlags & C_AREAPORTAL ) { + continue; + } + + if ( !PortalPassable( p ) ) { + continue; + } + + nodes2.push_back( p->otherNode( node ) ); + } } - - if ( !PortalPassable( p ) ) { - continue; - } - - FloodAreas_r( p->otherNode( node ) ); + nodes.swap( nodes2 ); + nodes2.clear(); } } @@ -668,7 +676,7 @@ static void FindAreas_r( node_t *node ){ return; } - FloodAreas_r( node ); + FloodAreas( node ); c_areas++; }