From 8bc56cd501923554990bec2c64388e9326b7f8e7 Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Wed, 14 Jan 2026 10:34:57 -0500 Subject: [PATCH] Defensive programming measures. Recent issue conversations are suggesting that it's no possible for footprints to contain null fields. Rather than blindly dereferencing field pointers in loops, check to make sure the field pointer is not null before dereferencing. --- 3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp | 2 ++ 3d-viewer/3d_canvas/create_layer_items.cpp | 2 ++ pcbnew/board.cpp | 2 ++ pcbnew/cross-probing.cpp | 5 +++++ pcbnew/dialogs/dialog_export_2581.cpp | 4 ++++ pcbnew/dialogs/dialog_find.cpp | 2 ++ pcbnew/dialogs/dialog_footprint_properties.cpp | 4 ++++ pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp | 6 ++++++ pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp | 2 ++ pcbnew/dialogs/panel_assign_component_classes.cpp | 4 ++++ pcbnew/drc/drc_test_provider_schematic_parity.cpp | 2 ++ pcbnew/pcb_edit_frame.cpp | 8 ++++++++ pcbnew/plot_board_layers.cpp | 4 ++++ pcbnew/plot_brditems_plotter.cpp | 2 ++ pcbnew/tools/board_editor_control.cpp | 4 ++++ pcbnew/tools/multichannel_tool.cpp | 2 ++ pcbnew/tools/pcb_control.cpp | 2 ++ pcbnew/tools/pcb_viewer_tools.cpp | 2 ++ pcbnew/widgets/pcb_properties_panel.cpp | 4 ++++ pcbnew/widgets/search_handlers.cpp | 2 ++ 20 files changed, 65 insertions(+) diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index eb0041e5ed..1b09deb406 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -208,6 +208,8 @@ void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2 if( !aFlags.test( LAYER_FP_TEXT ) ) continue; + wxCHECK2( field, continue ); + if( field->IsReference() && !aFlags.test( LAYER_FP_REFERENCES ) ) continue; diff --git a/3d-viewer/3d_canvas/create_layer_items.cpp b/3d-viewer/3d_canvas/create_layer_items.cpp index 779296895d..a2931aeac2 100644 --- a/3d-viewer/3d_canvas/create_layer_items.cpp +++ b/3d-viewer/3d_canvas/create_layer_items.cpp @@ -133,6 +133,8 @@ void transformFPTextToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer, if( !aFlags.test( LAYER_FP_TEXT ) ) continue; + wxCHECK2( field, continue ); + if( field->IsReference() && !aFlags.test( LAYER_FP_REFERENCES ) ) continue; diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 6d4cc2885e..2777a43085 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -1814,6 +1814,8 @@ BOARD_ITEM* BOARD::ResolveItem( const KIID& aID, bool aAllowNullptrReturn ) cons for( PCB_FIELD* field : footprint->GetFields() ) { + wxCHECK2( field, continue ); + if( field && field->m_Uuid == aID ) return field; } diff --git a/pcbnew/cross-probing.cpp b/pcbnew/cross-probing.cpp index d818af6939..c2a6b7d12d 100644 --- a/pcbnew/cross-probing.cpp +++ b/pcbnew/cross-probing.cpp @@ -555,8 +555,13 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) } nlohmann::ordered_map fields; + for( PCB_FIELD* field : footprint->GetFields() ) + { + wxCHECK2( field, continue ); + fields[field->GetCanonicalName()] = field->GetText(); + } component->SetFields( fields ); diff --git a/pcbnew/dialogs/dialog_export_2581.cpp b/pcbnew/dialogs/dialog_export_2581.cpp index fe5fc88368..4ea6b21de1 100644 --- a/pcbnew/dialogs/dialog_export_2581.cpp +++ b/pcbnew/dialogs/dialog_export_2581.cpp @@ -310,7 +310,11 @@ void DIALOG_EXPORT_2581::init() for( FOOTPRINT* fp : m_parent->GetBoard()->Footprints() ) { for( PCB_FIELD* field : fp->GetFields() ) + { + wxCHECK2( field, continue ); + options.insert( field->GetName() ); + } } std::vector items( options.begin(), options.end() ); diff --git a/pcbnew/dialogs/dialog_find.cpp b/pcbnew/dialogs/dialog_find.cpp index fb9024133e..6f47d355aa 100644 --- a/pcbnew/dialogs/dialog_find.cpp +++ b/pcbnew/dialogs/dialog_find.cpp @@ -250,6 +250,8 @@ void DIALOG_FIND::search( bool aDirection ) { for( PCB_FIELD* field : fp->GetFields() ) { + wxCHECK2( field, continue ); + if( field->Matches( frd, nullptr ) ) { found = true; diff --git a/pcbnew/dialogs/dialog_footprint_properties.cpp b/pcbnew/dialogs/dialog_footprint_properties.cpp index ef744734ef..c5acd0f898 100644 --- a/pcbnew/dialogs/dialog_footprint_properties.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties.cpp @@ -259,6 +259,8 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataToWindow() // Footprint Fields for( PCB_FIELD* srcField : m_footprint->GetFields() ) { + wxCHECK2( srcField, continue ); + PCB_FIELD field( *srcField ); field.SetText( m_footprint->GetBoard()->ConvertKIIDsToCrossReferences( field.GetText() ) ); @@ -532,6 +534,8 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataFromWindow() // Find any files referenced in the old fields that are not in the new fields for( PCB_FIELD* field : m_footprint->GetFields() ) { + wxCHECK2( field, continue ); + if( field->GetText().StartsWith( FILEEXT::KiCadUriPrefix ) ) { if( files.find( field->GetText() ) == files.end() ) diff --git a/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp b/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp index f84e7fa1c8..e2ec716e1d 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp @@ -337,7 +337,11 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow() // Footprint Fields for( PCB_FIELD* field : m_footprint->GetFields() ) + { + wxCHECK2( field, continue ); + m_fields->push_back( *field ); + } // Notify the grid wxGridTableMessage tmsg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->GetNumberRows() ); @@ -729,6 +733,8 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow() // Find any files referenced in the old fields that are not in the new fields for( PCB_FIELD* field : m_footprint->GetFields() ) { + wxCHECK2( field, continue ); + if( field->GetText().StartsWith( FILEEXT::KiCadUriPrefix ) ) { if( files.find( field->GetText() ) == files.end() ) diff --git a/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp b/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp index 64f6500d4c..db490b9493 100644 --- a/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp +++ b/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp @@ -477,6 +477,8 @@ bool DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::TransferDataFromWindow() for( PCB_FIELD* field : fp->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsReference() ) continue; diff --git a/pcbnew/dialogs/panel_assign_component_classes.cpp b/pcbnew/dialogs/panel_assign_component_classes.cpp index 354f334308..79734991fc 100644 --- a/pcbnew/dialogs/panel_assign_component_classes.cpp +++ b/pcbnew/dialogs/panel_assign_component_classes.cpp @@ -70,7 +70,11 @@ PANEL_ASSIGN_COMPONENT_CLASSES::PANEL_ASSIGN_COMPONENT_CLASSES( } for( const PCB_FIELD* field : fp->GetFields() ) + { + wxCHECK2( field, continue ); + fieldsSet.insert( field->GetName() ); + } } // Sort field names diff --git a/pcbnew/drc/drc_test_provider_schematic_parity.cpp b/pcbnew/drc/drc_test_provider_schematic_parity.cpp index 17aff91b36..cfa4e91225 100644 --- a/pcbnew/drc/drc_test_provider_schematic_parity.cpp +++ b/pcbnew/drc/drc_test_provider_schematic_parity.cpp @@ -208,6 +208,8 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist ) for( PCB_FIELD* field : footprint->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsReference() || field->IsValue() || field->IsComponentClass() ) continue; diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index e3500e6ea6..e7d37e3e64 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -2653,6 +2653,8 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew, for( PCB_FIELD* field : aExisting->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsReference() || field->IsValue() ) continue; @@ -2663,6 +2665,8 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew, for( PCB_FIELD* field : aNew->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsReference() || field->IsValue() ) continue; @@ -2773,6 +2777,8 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew, // Copy fields in accordance with the reset* flags for( PCB_FIELD* oldField : aExisting->GetFields() ) { + wxCHECK2( oldField, continue ); + // Reference and value are already handled if( oldField->IsReference() || oldField->IsValue() ) continue; @@ -2805,6 +2811,8 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew, // Check for any newly-added fields and set the update flag as appropriate for( PCB_FIELD* newField : aNew->GetFields() ) { + wxCHECK2( newField, continue ); + // Reference and value are already handled if( newField->IsReference() || newField->IsValue() ) continue; diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 51add89c93..8387f206e7 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -172,6 +172,8 @@ void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARA for( const PCB_FIELD* field : fp->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsReference() || field->IsValue() ) continue; @@ -1001,6 +1003,8 @@ void GenerateLayerPoly( SHAPE_POLY_SET* aResult, BOARD *aBoard, PLOTTER* aPlotte for( const PCB_FIELD* field : footprint->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsReference() && !aPlotReferences ) continue; diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 806d097ac9..dae8787ba6 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -433,6 +433,8 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint ) // Skip the reference and value texts that are handled specially for( PCB_FIELD* field : aFootprint->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsReference() || field->IsValue() ) continue; diff --git a/pcbnew/tools/board_editor_control.cpp b/pcbnew/tools/board_editor_control.cpp index e51ace8912..66e52b640b 100644 --- a/pcbnew/tools/board_editor_control.cpp +++ b/pcbnew/tools/board_editor_control.cpp @@ -505,7 +505,11 @@ int BOARD_EDITOR_CONTROL::ExportNetlist( const TOOL_EVENT& aEvent ) nlohmann::ordered_map fields; for( PCB_FIELD* field : footprint->GetFields() ) + { + wxCHECK2( field, continue ); + fields[field->GetCanonicalName()] = field->GetText(); + } component->SetFields( fields ); diff --git a/pcbnew/tools/multichannel_tool.cpp b/pcbnew/tools/multichannel_tool.cpp index 47b9489eed..95167baa09 100644 --- a/pcbnew/tools/multichannel_tool.cpp +++ b/pcbnew/tools/multichannel_tool.cpp @@ -1106,6 +1106,8 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( RULE_AREA* aRefArea, RULE_AREA* aT for( PCB_FIELD* refField : refFP->GetFields() ) { + wxCHECK2( refField, continue ); + PCB_FIELD* targetField = targetFP->GetField( refField->GetName() ); wxCHECK2( targetField, continue ); diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index 75171dfc74..e54fa9be44 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -938,6 +938,8 @@ static void pasteFootprintItemsToFootprintEditor( FOOTPRINT* aClipFootprint, BOA // for( PCB_FIELD* field : aClipFootprint->GetFields() ) { + wxCHECK2( field, continue ); + if( field->IsMandatory() ) { if( EDA_GROUP* parentGroup = field->GetParentGroup() ) diff --git a/pcbnew/tools/pcb_viewer_tools.cpp b/pcbnew/tools/pcb_viewer_tools.cpp index 882a3969b7..1351769c8c 100644 --- a/pcbnew/tools/pcb_viewer_tools.cpp +++ b/pcbnew/tools/pcb_viewer_tools.cpp @@ -224,6 +224,8 @@ int PCB_VIEWER_TOOLS::TextOutlines( const TOOL_EVENT& aEvent ) { for( PCB_FIELD* field : fp->GetFields() ) { + wxCHECK2( field, continue ); + view()->Update( field, KIGFX::REPAINT ); } diff --git a/pcbnew/widgets/pcb_properties_panel.cpp b/pcbnew/widgets/pcb_properties_panel.cpp index 5937cf7a20..c728ce72ff 100644 --- a/pcbnew/widgets/pcb_properties_panel.cpp +++ b/pcbnew/widgets/pcb_properties_panel.cpp @@ -381,7 +381,11 @@ void PCB_PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection ) FOOTPRINT* footprint = static_cast( item ); for( PCB_FIELD* field : footprint->GetFields() ) + { + wxCHECK2( field, continue ); + m_currentFieldNames.insert( field->GetCanonicalName() ); + } } const wxString groupFields = _HKI( "Fields" ); diff --git a/pcbnew/widgets/search_handlers.cpp b/pcbnew/widgets/search_handlers.cpp index 72055b83b3..cd370ff2bb 100644 --- a/pcbnew/widgets/search_handlers.cpp +++ b/pcbnew/widgets/search_handlers.cpp @@ -160,6 +160,8 @@ int FOOTPRINT_SEARCH_HANDLER::Search( const wxString& aQuery ) { for( PCB_FIELD* field : fp->GetFields() ) { + wxCHECK2( field, continue ); + if( field->Matches( frp, nullptr ) ) { found = true;