No more long-lived parsers.

We've had too many bugs from improper re-initialization.

Fixes https://gitlab.com/kicad/code/kicad/issues/9429
This commit is contained in:
Jeff Young 2021-10-31 19:57:52 +00:00
parent 6c05e5d1a8
commit ceceda37cc
9 changed files with 61 additions and 146 deletions

View File

@ -857,16 +857,20 @@ void DS_DATA_MODEL::SetPageLayout( const char* aPageLayout, bool Append, const w
if( ! Append )
ClearList();
DRAWING_SHEET_PARSER lp_parser( aPageLayout, wxT( "Sexpr_string" ) );
DRAWING_SHEET_PARSER parser( aPageLayout, wxT( "Sexpr_string" ) );
try
{
lp_parser.Parse( this );
parser.Parse( this );
}
catch( const IO_ERROR& ioe )
{
wxLogMessage( ioe.What() );
}
catch( const std::bad_alloc& )
{
wxLogMessage( "Memory exhaustion reading drawing sheet" );
}
}
@ -920,11 +924,11 @@ bool DS_DATA_MODEL::LoadDrawingSheet( const wxString& aFullFileName, bool Append
if( ! Append )
ClearList();
DRAWING_SHEET_PARSER pl_parser( buffer.get(), fullFileName );
DRAWING_SHEET_PARSER parser( buffer.get(), fullFileName );
try
{
pl_parser.Parse( this );
parser.Parse( this );
}
catch( const IO_ERROR& ioe )
{

View File

@ -2,6 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see AUTHORS.TXT for contributors.
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
* @author Kristoffer Ödmark
*
* This program is free software; you can redistribute it and/or
@ -25,7 +26,6 @@
#include <wx/clipbrd.h>
#include <wx/log.h>
#include <build_version.h>
#include <board.h>
#include <ignore.h>
#include <pad.h>
@ -401,19 +401,17 @@ BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe,
result = data.GetText().mb_str();
}
STRING_LINE_READER reader(result, wxT( "clipboard" ) );
STRING_LINE_READER reader( result, wxT( "clipboard" ) );
PCB_PARSER parser( &reader, aAppendToMe );
init( aProperties );
m_parser->SetLineReader( &reader );
m_parser->SetBoard( aAppendToMe );
BOARD_ITEM* item;
BOARD* board;
try
{
item = m_parser->Parse();
item = parser.Parse();
}
catch( const FUTURE_FORMAT_ERROR& )
{
@ -422,8 +420,8 @@ BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe,
}
catch( const PARSE_ERROR& parse_error )
{
if( m_parser->IsTooRecent() )
throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
if( parser.IsTooRecent() )
throw FUTURE_FORMAT_ERROR( parse_error, parser.GetRequiredVersion() );
else
throw;
}
@ -431,9 +429,8 @@ BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe,
if( item->Type() != PCB_T )
{
// The parser loaded something that was valid, but wasn't a board.
THROW_PARSE_ERROR( _( "Clipboard content is not KiCad compatible" ),
m_parser->CurSource(), m_parser->CurLine(),
m_parser->CurLineNumber(), m_parser->CurOffset() );
THROW_PARSE_ERROR( _( "Clipboard content is not KiCad compatible" ), parser.CurSource(),
parser.CurLine(), parser.CurLineNumber(), parser.CurOffset() );
}
else
{

View File

@ -1,11 +1,8 @@
/**
* @file kicad_netlist_reader.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2011 Jean-Pierre Charras.
* Copyright (C) 1992-2020 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 1992-2021 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -36,7 +33,9 @@ using namespace NL_T;
void KICAD_NETLIST_READER::LoadNetlist()
{
m_parser->Parse();
KICAD_NETLIST_PARSER parser( m_lineReader, m_netlist );
parser.Parse();
if( m_footprintReader )
{

View File

@ -1,10 +1,3 @@
#ifndef NETLIST_READER_H
#define NETLIST_READER_H
/**
* @file netlist_reader.h
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
@ -30,6 +23,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef NETLIST_READER_H
#define NETLIST_READER_H
#include <boost/ptr_container/ptr_vector.hpp>
#include <macros.h>
@ -172,11 +168,6 @@ public:
*/
virtual void LoadNetlist() = 0;
/**
* @return the #LINE_READER associated with the #NETLIST_READER.
*/
LINE_READER* GetLineReader();
protected:
NETLIST* m_netlist; ///< The net list to read the file(s) into.
bool m_loadFootprintFilters; ///< Load the component footprint filters section if true.
@ -280,10 +271,6 @@ class KICAD_NETLIST_PARSER : public NETLIST_LEXER
public:
KICAD_NETLIST_PARSER( LINE_READER* aReader, NETLIST* aNetlist );
void SetLineReader( LINE_READER* aLineReader );
void SetNetlist( NETLIST* aNetlist ) { m_netlist = aNetlist; }
/**
* Function Parse
* parse the full netlist
@ -364,20 +351,13 @@ public:
KICAD_NETLIST_READER( LINE_READER* aLineReader,
NETLIST* aNetlist,
CMP_READER* aFootprintLinkReader = nullptr ) :
NETLIST_READER( aLineReader, aNetlist, aFootprintLinkReader ),
m_parser( new KICAD_NETLIST_PARSER( aLineReader, aNetlist ) )
{
}
NETLIST_READER( aLineReader, aNetlist, aFootprintLinkReader )
{ }
virtual ~KICAD_NETLIST_READER()
{
delete m_parser;
}
{ }
virtual void LoadNetlist() override;
private:
KICAD_NETLIST_PARSER* m_parser; ///< The s-expression format parser.
};

View File

@ -72,48 +72,20 @@ class PROGRESS_REPORTER;
class PCB_PARSER : public PCB_LEXER
{
public:
PCB_PARSER( LINE_READER* aReader = nullptr ) :
PCB_PARSER( LINE_READER* aReader, BOARD* aBoard = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr, unsigned aLineCount = 0 ) :
PCB_LEXER( aReader ),
m_board( nullptr ),
m_resetKIIDs( false ),
m_progressReporter( nullptr ),
m_board( aBoard ),
m_resetKIIDs( aBoard != nullptr ),
m_progressReporter( aProgressReporter ),
m_lastProgressTime( std::chrono::steady_clock::now() ),
m_lineCount( 0 )
m_lineCount( aLineCount )
{
init();
}
// ~PCB_PARSER() {}
/**
* Set @a aLineReader into the parser, and returns the previous one, if any.
*
* @param aReader is what to read from for tokens, no ownership is received.
* @return LINE_READER* - previous LINE_READER or NULL if none.
*/
LINE_READER* SetLineReader( LINE_READER* aReader )
{
LINE_READER* ret = PopReader();
PushReader( aReader );
return ret;
}
void SetBoard( BOARD* aBoard )
{
init();
m_board = aBoard;
if( aBoard != nullptr )
m_resetKIIDs = true;
}
void SetProgressReporter( PROGRESS_REPORTER* aProgressReporter, unsigned aLineCount )
{
m_progressReporter = aProgressReporter;
m_lastProgressTime = std::chrono::steady_clock::now();
m_lineCount = aLineCount;
}
BOARD_ITEM* Parse();
/**

View File

@ -262,16 +262,10 @@ void FP_CACHE::Load()
// Queue I/O errors so only files that fail to parse don't get loaded.
try
{
FILE_LINE_READER reader( fn.GetFullPath() );
FILE_LINE_READER reader( fn.GetFullPath() );
PCB_PARSER parser( &reader );
m_owner->m_parser->SetLineReader( &reader );
// For better or worse (mostly worse), the parser is a long-lived object.
// Make sure we start with a fresh state.
m_owner->m_parser->InitParserState();
m_owner->m_parser->SetBoard( nullptr ); // calls PCB_PARSER::init()
FOOTPRINT* footprint = (FOOTPRINT*) m_owner->m_parser->Parse();
FOOTPRINT* footprint = (FOOTPRINT*) parser.Parse();
wxString fpName = fn.GetName();
footprint->SetFPID( LIB_ID( wxEmptyString, fpName ) );
@ -379,18 +373,17 @@ BOARD_ITEM* PCB_PLUGIN::Parse( const wxString& aClipboardSourceInput )
{
std::string input = TO_UTF8( aClipboardSourceInput );
STRING_LINE_READER reader( input, wxT( "clipboard" ) );
m_parser->SetLineReader( &reader );
STRING_LINE_READER reader( input, wxT( "clipboard" ) );
PCB_PARSER parser( &reader );
try
{
return m_parser->Parse();
return parser.Parse();
}
catch( const PARSE_ERROR& parse_error )
{
if( m_parser->IsTooRecent() )
throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
if( parser.IsTooRecent() )
throw FUTURE_FORMAT_ERROR( parse_error, parser.GetRequiredVersion() );
else
throw;
}
@ -2285,7 +2278,6 @@ void PCB_PLUGIN::format( const ZONE* aZone, int aNestLevel ) const
PCB_PLUGIN::PCB_PLUGIN( int aControlFlags ) :
m_cache( nullptr ),
m_ctl( aControlFlags ),
m_parser( new PCB_PARSER() ),
m_mapping( new NETINFO_MAPPING() )
{
init( nullptr );
@ -2296,7 +2288,6 @@ PCB_PLUGIN::PCB_PLUGIN( int aControlFlags ) :
PCB_PLUGIN::~PCB_PLUGIN()
{
delete m_cache;
delete m_parser;
delete m_mapping;
}
@ -2336,15 +2327,12 @@ BOARD* PCB_PLUGIN::DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const PROPE
{
init( aProperties );
m_parser->SetLineReader( &aReader );
m_parser->SetBoard( aAppendToMe );
m_parser->SetProgressReporter( aProgressReporter, aLineCount );
BOARD* board;
PCB_PARSER parser( &aReader, aAppendToMe, aProgressReporter, aLineCount );
BOARD* board;
try
{
board = dynamic_cast<BOARD*>( m_parser->Parse() );
board = dynamic_cast<BOARD*>( parser.Parse() );
}
catch( const FUTURE_FORMAT_ERROR& )
{
@ -2353,8 +2341,8 @@ BOARD* PCB_PLUGIN::DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const PROPE
}
catch( const PARSE_ERROR& parse_error )
{
if( m_parser->IsTooRecent() )
throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
if( parser.IsTooRecent() )
throw FUTURE_FORMAT_ERROR( parse_error, parser.GetRequiredVersion() );
else
throw;
}
@ -2362,8 +2350,8 @@ BOARD* PCB_PLUGIN::DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const PROPE
if( !board )
{
// The parser loaded something that was valid, but wasn't a board.
THROW_PARSE_ERROR( _( "This file does not contain a PCB." ), m_parser->CurSource(),
m_parser->CurLine(), m_parser->CurLineNumber(), m_parser->CurOffset() );
THROW_PARSE_ERROR( _( "This file does not contain a PCB." ), parser.CurSource(),
parser.CurLine(), parser.CurLineNumber(), parser.CurOffset() );
}
return board;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 CERN.
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -297,7 +297,6 @@ protected:
STRING_FORMATTER m_sf;
OUTPUTFORMATTER* m_out; ///< output any Format()s to this, no ownership
int m_ctl;
PCB_PARSER* m_parser;
NETINFO_MAPPING* m_mapping; ///< mapping for net codes, so only not empty net codes
///< are stored with consecutive integers as net codes
};

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see AUTHORS.TXT for contributors.
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -25,7 +25,6 @@
#include <cstdio>
#include <string>
#include <common.h>
#include <profile.h>
@ -35,11 +34,7 @@
#include <plugins/kicad/pcb_plugin.h>
#include <plugins/kicad/pcb_parser.h>
#include <richio.h>
#include <wx/cmdline.h>
#include <qa_utils/stdstream_line_reader.h>
#include <qa_utils/utility_registry.h>
using PARSE_DURATION = std::chrono::microseconds;
@ -57,10 +52,7 @@ bool parse( std::istream& aStream, bool aVerbose )
STDISTREAM_LINE_READER reader;
reader.SetStream( aStream );
PCB_PARSER parser;
parser.SetLineReader( &reader );
PCB_PARSER parser( &reader );
BOARD_ITEM* board = nullptr;
PARSE_DURATION duration{};
@ -110,10 +102,9 @@ int pcb_parser_main_func( int argc, char** argv )
wxMessageOutput::Set( new wxMessageOutputStderr );
wxCmdLineParser cl_parser( argc, argv );
cl_parser.SetDesc( g_cmdLineDesc );
cl_parser.AddUsageText(
_( "This program parses PCB files, either from the "
"stdin stream or from the given filenames. This can be used either for "
"standalone testing of the parser or for fuzz testing." ) );
cl_parser.AddUsageText( _( "This program parses PCB files, either from the stdin stream or "
"from the given filenames. This can be used either for standalone "
"testing of the parser or for fuzz testing." ) );
int cmd_parsed_ok = cl_parser.Parse();
if( cmd_parsed_ok != 0 )
@ -122,11 +113,9 @@ int pcb_parser_main_func( int argc, char** argv )
return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
}
const bool verbose = cl_parser.Found( "verbose" );
bool ok = true;
const auto file_count = cl_parser.GetParamCount();
const bool verbose = cl_parser.Found( "verbose" );
bool ok = true;
const size_t file_count = cl_parser.GetParamCount();
if( file_count == 0 )
{
@ -163,5 +152,6 @@ int pcb_parser_main_func( int argc, char** argv )
}
static bool registered = UTILITY_REGISTRY::Register(
{ "pcb_parser", "Parse a KiCad PCB file", pcb_parser_main_func } );
static bool registered = UTILITY_REGISTRY::Register( { "pcb_parser",
"Parse a KiCad PCB file",
pcb_parser_main_func } );

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -69,27 +69,13 @@ void DumpBoardToFile( BOARD& board, const std::string& aFilename )
}
std::unique_ptr<BOARD_ITEM> ReadBoardItemFromFile( const std::string& aFilename )
{
FILE_LINE_READER reader( aFilename );
PCB_PARSER parser;
parser.SetLineReader( &reader );
return std::unique_ptr<BOARD_ITEM>( parser.Parse() );
}
std::unique_ptr<BOARD_ITEM> ReadBoardItemFromStream( std::istream& aStream )
{
// Take input from stdin
STDISTREAM_LINE_READER reader;
reader.SetStream( aStream );
PCB_PARSER parser;
parser.SetLineReader( &reader );
PCB_PARSER parser( &reader );
std::unique_ptr<BOARD_ITEM> board;
try