From 31b788c04fe2db622fc73d097d0d049507f6a41e Mon Sep 17 00:00:00 2001 From: Jeff Young <jeff@rokeby.ie> Date: Tue, 11 Mar 2025 15:08:13 +0000 Subject: [PATCH] Add a bit of protection from integer overflows. Fixes https://gitlab.com/kicad/code/kicad/-/issues/19660 --- common/dialogs/panel_setup_netclasses.cpp | 38 +++++++++++++++++++---- include/board_design_settings.h | 2 ++ include/dialogs/panel_setup_netclasses.h | 1 + pcbnew/board_design_settings.cpp | 3 +- pcbnew/drc/drc_engine.cpp | 18 +++++++++++ 5 files changed, 55 insertions(+), 7 deletions(-) diff --git a/common/dialogs/panel_setup_netclasses.cpp b/common/dialogs/panel_setup_netclasses.cpp index 9e4658c853..51beec93f4 100644 --- a/common/dialogs/panel_setup_netclasses.cpp +++ b/common/dialogs/panel_setup_netclasses.cpp @@ -35,6 +35,7 @@ #include <dialogs/panel_setup_netclasses.h> #include <tool/tool_manager.h> #include <pcb_painter.h> +#include <board_design_settings.h> #include <string_utils.h> #include <view/view.h> #include <widgets/grid_color_swatch_helpers.h> @@ -504,16 +505,16 @@ bool PANEL_SETUP_NETCLASSES::TransferDataFromWindow() wxASSERT_MSG( lineIdx >= 0, "Line style name not found." ); + // clang-format off nc->SetClearance( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_CLEARANCE ) ); nc->SetTrackWidth( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_TRACKSIZE ) ); nc->SetViaDiameter( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_VIASIZE ) ); nc->SetViaDrill( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_VIADRILL ) ); nc->SetuViaDiameter( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_uVIASIZE ) ); nc->SetuViaDrill( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_uVIADRILL ) ); - nc->SetDiffPairWidth( - m_netclassGrid->GetOptionalUnitValue( aRow, GRID_DIFF_PAIR_WIDTH ) ); - nc->SetDiffPairGap( m_netclassGrid->GetOptionalUnitValue( aRow, - GRID_DIFF_PAIR_GAP ) ); + nc->SetDiffPairWidth( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_DIFF_PAIR_WIDTH ) ); + nc->SetDiffPairGap( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_DIFF_PAIR_GAP ) ); + // clang-format on if( !nc->IsDefault() ) { @@ -590,6 +591,26 @@ bool PANEL_SETUP_NETCLASSES::validateNetclassName( int aRow, const wxString& aNa } +bool PANEL_SETUP_NETCLASSES::validateNetclassClearance( int aRow ) +{ + // Clip clearance. This is not a nag; we can end up with overflow errors and very poor + // performance if the clearance is too large. + + std::optional<int> clearance = m_netclassGrid->GetOptionalUnitValue( aRow, GRID_CLEARANCE ); + + if( clearance.has_value() && clearance.value() > MAXIMUM_CLEARANCE ) + { + wxString msg = wxString::Format( _( "Clearance was too large. It has been clipped to %s." ), + m_frame->StringFromValue( MAXIMUM_CLEARANCE, true ) ); + PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_netclassGrid, aRow, GRID_CLEARANCE ); + m_netclassGrid->SetUnitValue( aRow, GRID_CLEARANCE, MAXIMUM_CLEARANCE ); + return false; + } + + return true; +} + + void PANEL_SETUP_NETCLASSES::OnNetclassGridCellChanging( wxGridEvent& event ) { if( event.GetCol() == GRID_NAME ) @@ -615,6 +636,10 @@ void PANEL_SETUP_NETCLASSES::OnNetclassGridCellChanging( wxGridEvent& event ) event.Veto(); } } + else if( event.GetCol() == GRID_CLEARANCE ) + { + validateNetclassClearance( event.GetRow() ); + } } @@ -901,8 +926,6 @@ bool PANEL_SETUP_NETCLASSES::Validate() if( !m_netclassGrid->CommitPendingChanges() || !m_assignmentGrid->CommitPendingChanges() ) return false; - wxString msg; - // Test net class parameters. for( int row = 0; row < m_netclassGrid->GetNumberRows(); row++ ) { @@ -912,6 +935,9 @@ bool PANEL_SETUP_NETCLASSES::Validate() if( !validateNetclassName( row, netclassName, false ) ) return false; + + if( !validateNetclassClearance( row ) ) + return false; } return true; diff --git a/include/board_design_settings.h b/include/board_design_settings.h index 5adb2a3eee..24a5720ecf 100644 --- a/include/board_design_settings.h +++ b/include/board_design_settings.h @@ -101,6 +101,8 @@ #define MINIMUM_ERROR_SIZE_MM 0.001 // For arc approximation #define MAXIMUM_ERROR_SIZE_MM 0.1 // For arc approximation +#define MAXIMUM_CLEARANCE pcbIUScale.mmToIU( 500 ) // to prevent int-overflows + // Min/max values used in dialogs to validate settings #define MINIMUM_LINE_WIDTH_MM 0.005 // minimal line width entered in a dialog #define MAXIMUM_LINE_WIDTH_MM 100.0 // max line width entered in a dialog diff --git a/include/dialogs/panel_setup_netclasses.h b/include/dialogs/panel_setup_netclasses.h index 174f6556ac..28e8e48a77 100644 --- a/include/dialogs/panel_setup_netclasses.h +++ b/include/dialogs/panel_setup_netclasses.h @@ -65,6 +65,7 @@ private: void onUnitsChanged( wxCommandEvent& aEvent ); bool validateNetclassName( int aRow, const wxString& aName, bool focusFirst = true ); + bool validateNetclassClearance( int aRow ); void rebuildNetclassDropdowns(); diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index 5be62f14b0..768691fd36 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -1311,7 +1311,8 @@ int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue() const biggest = std::max( biggest, constraint.Value().Min() ); } - return biggest; + // Clip to avoid integer overflows in subsequent calculations + return std::min( biggest, MAXIMUM_CLEARANCE ); } diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index 35bc60db92..b0b38c5ff5 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -746,6 +746,24 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO if( c->constraint.m_Value.HasMax() ) constraint .m_Value.SetMax( c->constraint.m_Value.Max() ); + switch( c->constraint.m_Type ) + { + case CLEARANCE_CONSTRAINT: + case COURTYARD_CLEARANCE_CONSTRAINT: + case SILK_CLEARANCE_CONSTRAINT: + case HOLE_CLEARANCE_CONSTRAINT: + case EDGE_CLEARANCE_CONSTRAINT: + case PHYSICAL_CLEARANCE_CONSTRAINT: + case PHYSICAL_HOLE_CLEARANCE_CONSTRAINT: + if( constraint.m_Value.Min() > MAXIMUM_CLEARANCE ) + constraint.m_Value.SetMin( MAXIMUM_CLEARANCE ); + + break; + + default: + break; + } + // While the expectation would be to OR the disallow flags, we've already // masked them down to aItem's type -- so we're really only looking for a // boolean here.