From 2a026bd882860489196334660023f6355a19a14b Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 29 Feb 2020 17:25:52 +0100 Subject: [PATCH] spread_footprints.cpp: try to avoid integer overflow when spreading footprints. In rare cases (one known case) sizes of areas used as container when spreading footprints can become negative, thus hanging pcbnew. Happens if many footprints are very big (say 80cm). Now if there is no room to place footprints, some are stacked. --- pcbnew/autorouter/spread_footprints.cpp | 55 ++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/pcbnew/autorouter/spread_footprints.cpp b/pcbnew/autorouter/spread_footprints.cpp index 663409167d..8e7129d8ff 100644 --- a/pcbnew/autorouter/spread_footprints.cpp +++ b/pcbnew/autorouter/spread_footprints.cpp @@ -108,6 +108,7 @@ void spreadRectangles( CRectPlacement& aPlacementArea, // Add all subrects CSubRectArray::iterator it; + for( it = vecSubRects.begin(); it != vecSubRects.end(); ) { CRectPlacement::TRect r( 0, 0, it->w, it->h ); @@ -116,11 +117,26 @@ void spreadRectangles( CRectPlacement& aPlacementArea, if( !bPlaced ) // No room to place the rectangle: enlarge area and retry { - areaSizeX = ceil(areaSizeX * 1.1); - areaSizeY = ceil(areaSizeY * 1.1); - aPlacementArea.Init( areaSizeX, areaSizeY ); - it = vecSubRects.begin(); - continue; + bool retry = false; + + if( areaSizeX < INT_MAX/2 ) + { + retry = true; + areaSizeX = areaSizeX * 1.2; + } + + if( areaSizeX < INT_MAX/2 ) + { + retry = true; + areaSizeY = areaSizeY * 1.2; + } + + if( retry ) + { + aPlacementArea.Init( areaSizeX, areaSizeY ); + it = vecSubRects.begin(); + continue; + } } // When correctly placed in a placement area, the coords are returned in r.x and r.y @@ -212,6 +228,9 @@ void SpreadFootprints( std::vector* aFootprints, footprintListBySheet.clear(); subsurface = 0.0; + int fp_max_width = 0; + int fp_max_height = 0; + for( unsigned ii = 0; ii < footprintList.size(); ii++ ) { MODULE* footprint = footprintList[ii]; @@ -225,13 +244,21 @@ void SpreadFootprints( std::vector* aFootprints, footprintListBySheet.push_back( footprint ); subsurface += footprint->GetArea( PADDING ); + // Calculate min size of placement area: + EDA_RECT bbox = footprint->GetFootprintRect(); + fp_max_width = std::max( fp_max_width, bbox.GetWidth() ); + fp_max_height = std::max( fp_max_height, bbox.GetHeight() ); + if( islastItem ) { // end of the footprint sublist relative to the same sheet path // calculate placement of the current sublist EDA_RECT freeArea; int Xsize_allowed = (int) ( sqrt( subsurface ) * 4.0 / 3.0 ); + Xsize_allowed = std::max( fp_max_width, Xsize_allowed ); + int Ysize_allowed = (int) ( subsurface / Xsize_allowed ); + Ysize_allowed = std::max( fp_max_height, Ysize_allowed ); freeArea.SetWidth( Xsize_allowed ); freeArea.SetHeight( Ysize_allowed ); @@ -276,10 +303,17 @@ void SpreadFootprints( std::vector* aFootprints, if( pass == 0 ) { int Xsize_allowed = (int) ( sqrt( placementsurface ) * 4.0 / 3.0 ); + + if( Xsize_allowed < 0 || Xsize_allowed > INT_MAX/2 ) + Xsize_allowed = INT_MAX/2; + int Ysize_allowed = (int) ( placementsurface / Xsize_allowed ); + + if( Ysize_allowed < 0 || Ysize_allowed > INT_MAX/2 ) + Ysize_allowed = INT_MAX/2; + CRectPlacement placementArea; CSubRectArray vecSubRects; - fillRectList( vecSubRects, placementSheetAreas ); spreadRectangles( placementArea, vecSubRects, Xsize_allowed, Ysize_allowed ); @@ -288,6 +322,15 @@ void SpreadFootprints( std::vector* aFootprints, TSubRect& srect = vecSubRects[it]; wxPoint pos( srect.x*scale, srect.y*scale ); wxSize size( srect.w*scale, srect.h*scale ); + + // Avoid too large coordinates: Overlapping components + // are better than out of screen components + if( (uint64_t)pos.x + (uint64_t)size.x > INT_MAX/2 ) + pos.x = 0; + + if( (uint64_t)pos.y + (uint64_t)size.y > INT_MAX/2 ) + pos.y = 0; + placementSheetAreas[srect.n].SetOrigin( pos ); placementSheetAreas[srect.n].SetSize( size ); }