Fix hang on recursive substitution `defines, bug443.

This commit is contained in:
Wilson Snyder 2012-02-23 21:37:49 -05:00
parent c8e4b1fc84
commit 09c10492ab
7 changed files with 81 additions and 12 deletions

View File

@ -18,6 +18,9 @@ indicates the contributor was also the author of the fix; Thanks!
**** Fix hang when functions inside begin block. [David Welch]
**** Fix hang on recursive substitution `defines, bug443. [Alex Solomatnikov]
* Verilator 3.831 2012/01/20
** Support SystemC 2.3.0 prerelease. This requires setting the new

View File

@ -34,6 +34,7 @@
//======================================================================
class V3PreLex;
class V3PreProcImp;
// Token codes
@ -126,16 +127,23 @@ void yy_delete_buffer( YY_BUFFER_STATE b );
class VPreStream {
public:
FileLine* m_curFilelinep; // Current processing point (see also m_tokFilelinep)
V3PreLex* m_lexp; // Lexer, for resource tracking
deque<string> m_buffers; // Buffer of characters to process
int m_ignNewlines; // Ignore multiline newlines
bool m_eof; // "EOF" buffer
bool m_file; // Buffer is start of new file
int m_termState; // Termination fsm
VPreStream(FileLine* fl)
: m_curFilelinep(fl), m_ignNewlines(0),
VPreStream(FileLine* fl, V3PreLex* lexp)
: m_curFilelinep(fl), m_lexp(lexp),
m_ignNewlines(0),
m_eof(false), m_file(false), m_termState(0) {
lexStreamDepthAdd(1);
}
~VPreStream() {}
~VPreStream() {
lexStreamDepthAdd(-1);
}
private:
void lexStreamDepthAdd(int delta);
};
//======================================================================
@ -145,6 +153,7 @@ class V3PreLex {
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
V3PreProcImp* m_preimpp; // Preprocessor lexor belongs to
stack<VPreStream*> m_streampStack; // Stack of processing files
int m_streamDepth; // Depth of stream processing
YY_BUFFER_STATE m_bufferState; // Flex state
FileLine* m_tokFilelinep; // Starting position of current token
@ -166,6 +175,7 @@ class V3PreLex {
// CONSTRUCTORS
V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep) {
m_preimpp = preimpp;
m_streamDepth = 0;
m_keepComments = 0;
m_keepWhitespace = 1;
m_pedantic = false;
@ -207,6 +217,9 @@ class V3PreLex {
void dumpSummary();
void dumpStack();
void unused();
// Called by VPreStream
void streamDepthAdd(int delta) { m_streamDepth += delta; }
int streamDepth() const { return m_streamDepth; }
/// Utility
static int debug();
static void debug(int level);
@ -219,4 +232,6 @@ private:
void scanSwitchStream(VPreStream* streamp);
};
inline void VPreStream::lexStreamDepthAdd(int delta) { m_lexp->streamDepthAdd(delta); }
#endif // Guard

View File

@ -432,7 +432,7 @@ string V3PreLex::endOfStream(bool& againr) {
void V3PreLex::initFirstBuffer(FileLine* filelinep) {
// Called from constructor to make first buffer
// yy_create_buffer also sets yy_fill_buffer=1 so reads from YY_INPUT
VPreStream* streamp = new VPreStream(filelinep);
VPreStream* streamp = new VPreStream(filelinep, this);
streamp->m_eof = true;
m_streampStack.push(streamp);
//
@ -443,10 +443,16 @@ void V3PreLex::initFirstBuffer(FileLine* filelinep) {
void V3PreLex::scanNewFile(FileLine* filelinep) {
// Called on new open file. scanBytesBack will be called next.
VPreStream* streamp = new VPreStream(filelinep);
m_tokFilelinep = curFilelinep();
streamp->m_file = true;
scanSwitchStream(streamp);
if (streamDepth() > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
// The recursive `include in VPreProcImp should trigger first
yyerrorf("Recursive `define or other nested inclusion");
curStreamp()->m_eof = true; // Fake it to stop recursion
} else {
VPreStream* streamp = new VPreStream(filelinep, this);
m_tokFilelinep = curFilelinep();
streamp->m_file = true;
scanSwitchStream(streamp);
}
}
void V3PreLex::scanBytes(const string& str) {
@ -455,9 +461,16 @@ void V3PreLex::scanBytes(const string& str) {
// to take effect immediately, in the middle of the current buffer
// Also we don't use scan_bytes that would set yy_fill_buffer
// which would force Flex to bypass our YY_INPUT routine.
VPreStream* streamp = new VPreStream(curFilelinep());
streamp->m_buffers.push_front(str);
scanSwitchStream(streamp);
if (streamDepth() > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
// More streams if recursive `define with complex insertion
// More buffers mostly if something internal goes funky
yyerrorf("Recursive `define or other nested inclusion");
curStreamp()->m_eof = true; // Fake it to stop recursion
} else {
VPreStream* streamp = new VPreStream(curFilelinep(), this);
streamp->m_buffers.push_front(str);
scanSwitchStream(streamp);
}
}
void V3PreLex::scanSwitchStream(VPreStream* streamp) {

View File

@ -112,7 +112,7 @@ struct V3PreProcImp : public V3PreProc {
typedef std::map<string,V3Define> DefinesMap;
typedef V3InFilter::StrList StrList;
// debug() -> see V3PreShellImp::debug
// debug() -> see V3PreShellImp::debug; use --debugi-V3PreShell
// Defines list
DefinesMap m_defines; ///< Map of defines

View File

@ -50,6 +50,8 @@ public:
enum MiscConsts {
DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error
INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error
STREAM_DEPTH_LEVEL_MAX = 2000, // How many streams deep (sometimes `def deep) before an error
// // Set more than DEFINE_RECURSION_LEVEL_MAX or INCLUDE_DEPTH_MAX
NEWLINES_VS_TICKLINE = 20 // Use `line in place of this many newlines
};

View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_pp_circdef_bad.v:\d+: Recursive `define or other nested inclusion
.*
%Error: Exiting due to.*',
);
ok(1);
1;

View File

@ -0,0 +1,13 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2011 by Wilson Snyder.
//
// bug445
`define WIDTH 12
`define SEL_NUM_BITS `WIDTH-`SEL_NUM_BITS +: `SEL_NUM_BITS
`define SEL_BITS `WIDTH-`SEL_NUM_BITS +: `SEL_NUM_BITS
`define ADDR_BITS 0 +: `WIDTH-`SEL_NUM_BITS
typedef logic [`SEL_NUM_BITS-1:0] d_t;