diff --git a/Changes b/Changes index e358b1874..e17a43cef 100644 --- a/Changes +++ b/Changes @@ -25,7 +25,7 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix multithreaded yield behavior when no work. [Patrick Stewart] **** Fix bad-syntax crashes, bug1548, bug1550-1553, bug1557-1560, bug1563, - bug1573. [Eric Rippey] + bug1573, bug1574. [Eric Rippey] **** Benchmark --protect-lib runtime, bug1519. [Todd Strader] diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index ed236cce6..667e8ba74 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -118,6 +118,8 @@ public: V3PreProc* m_preprocp; ///< Object we're holding data for V3PreLex* m_lexp; ///< Current lexer state (NULL = closed) std::stack m_includeStack; ///< Stack of includers above current m_lexp + int m_lastLineno; // Last line number (stall detection) + int m_tokensOnLine; // Number of tokens on line (stall detection) enum ProcState { ps_TOP, ps_DEFNAME_UNDEF, ps_DEFNAME_DEFINE, @@ -266,6 +268,8 @@ public: m_finFilelinep = NULL; m_lexp = NULL; m_preprocp = NULL; + m_lastLineno = 0; + m_tokensOnLine = 0; } void configure(FileLine* filelinep) { // configure() separate from constructor to avoid calling abstract functions @@ -889,6 +893,15 @@ int V3PreProcImp::getRawToken() { int tok = m_lexp->lex(); if (debug()>=5) debugToken(tok, "RAW"); + if (m_lastLineno != m_lexp->m_tokFilelinep->lineno()) { + m_lastLineno = m_lexp->m_tokFilelinep->lineno(); + m_tokensOnLine = 0; + } else if (++m_tokensOnLine > LINE_TOKEN_MAX) { + error("Too many preprocessor tokens on a line (>"+cvtToStr(LINE_TOKEN_MAX) + +"); perhaps recursive `define"); + tok = VP_EOF_ERROR; + } + if (tok==VP_EOF || tok==VP_EOF_ERROR) { // An error might be in an unexpected point, so stop parsing if (tok==VP_EOF_ERROR) forceEof(); diff --git a/src/V3PreProc.h b/src/V3PreProc.h index 0422d0e5f..2ff1d7eb0 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -49,6 +49,7 @@ public: // CONSTANTS enum MiscConsts { DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error + LINE_TOKEN_MAX = 20000, // How many tokens on a line 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 diff --git a/test_regress/t/t_pp_circ_subst_bad.out b/test_regress/t/t_pp_circ_subst_bad.out new file mode 100644 index 000000000..a9e9b211a --- /dev/null +++ b/test_regress/t/t_pp_circ_subst_bad.out @@ -0,0 +1,3 @@ +%Error: t/t_pp_circ_subst_bad.v:7: Too many preprocessor tokens on a line (>20000); perhaps recursive `define +%Error: t/t_pp_circ_subst_bad.v:7: syntax error, unexpected IDENTIFIER +%Error: Exiting due to diff --git a/test_regress/t/t_pp_circ_subst_bad.pl b/test_regress/t/t_pp_circ_subst_bad.pl new file mode 100755 index 000000000..b09f43e8b --- /dev/null +++ b/test_regress/t/t_pp_circ_subst_bad.pl @@ -0,0 +1,18 @@ +#!/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. + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_pp_circ_subst_bad.v b/test_regress/t/t_pp_circ_subst_bad.v new file mode 100644 index 000000000..ef10ca1ce --- /dev/null +++ b/test_regress/t/t_pp_circ_subst_bad.v @@ -0,0 +1,7 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2019 by Wilson Snyder. + +`define e fun `e +`e