Added width cap for unsized expressions.

Unsized expressions can expand to extremely large widths. Usually this
is actually a mistake in the source code, but it can lead to the compiler
temporarily using extremely large amounts of memory, or in the worst
case, crashing. This adds a cap on the width of unsized expressions (by
default 65536 bits, but overridable by the user), and causes a warning
message to be output when the cap is reached.
This commit is contained in:
Martin Whitaker 2014-02-27 19:20:20 +00:00
parent 1f81d4c081
commit 5dcd2e8957
9 changed files with 63 additions and 19 deletions

View File

@ -1,7 +1,7 @@
#ifndef __compiler_H
#define __compiler_H
/*
* Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -36,6 +36,11 @@
*/
extern unsigned integer_width;
/*
* The width_cap is the width limit for unsized expressions.
*/
extern unsigned width_cap;
/*
* This is the maximum number of recursive module loops allowed within
* a generate block.

View File

@ -4,7 +4,7 @@
%{
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -92,6 +92,8 @@ int cmdfile_stack_ptr = 0;
"+vhdl-libdir+" { BEGIN(PLUS_ARGS); return TOK_VHDL_LIBDIR; }
"+width-cap+" { BEGIN(PLUS_ARGS); return TOK_WIDTH_CAP; }
/* If it is not any known plus-flag, return the generic form. */
"+"[^\n \t\b\f\r+]* {
cflval.text = strdup(yytext);

View File

@ -1,6 +1,6 @@
%{
/*
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -61,6 +61,7 @@ static void translate_file_name(char*text)
%token TOK_Da TOK_Dc TOK_Dv TOK_Dy
%token TOK_DEFINE TOK_INCDIR TOK_INTEGER_WIDTH TOK_LIBDIR TOK_LIBDIR_NOCASE
%token TOK_LIBEXT TOK_PARAMETER TOK_TIMESCALE TOK_VHDL_WORK TOK_VHDL_LIBDIR
%token TOK_WIDTH_CAP
%token <text> TOK_PLUSARG TOK_PLUSWORD TOK_STRING
%%
@ -191,6 +192,13 @@ item
free(tmp);
}
| TOK_WIDTH_CAP TOK_PLUSARG
{ char*tmp = substitutions($2);
free($2);
width_cap = strtoul(tmp,0,10);
free(tmp);
}
/* The +<word> tokens that are not otherwise matched, are
ignored. The skip_args rule arranges for all the argument words
to be consumed. */

View File

@ -1,7 +1,7 @@
#ifndef __globals_H
#define __globals_H
/*
* Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -24,6 +24,9 @@
/* This is the integer-width argument that will be passed to ivl. */
extern unsigned integer_width;
/* This is the width-cap argument that will be passed to ivl. */
extern unsigned width_cap;
extern const char*vhdlpp_work;
extern const char**vhdlpp_libdir;
extern unsigned vhdlpp_libdir_cnt;

View File

@ -1,4 +1,4 @@
.TH iverilog 1 "April 2nd, 2013" "" "Version %M.%m.%n %E"
.TH iverilog 1 "February 26th, 2014" "" "Version %M.%m.%n %E"
.SH NAME
iverilog - Icarus Verilog compiler
@ -462,6 +462,12 @@ This allows the programmer to select the width for integer variables
in the Verilog source. The default is 32, the value can be any desired
integer value.
.TP 8
.B +width-cap+\fIvalue\fP
This allows the programmer to select the width cap for unsized expressions.
If the calculated width for an unsized expression exceeds this value, the
compiler will issue a warning and limit the expression width to this value.
.SH "VARIABLES IN COMMAND FILES"
In certain cases, iverilog supports variables in command files. These
@ -515,7 +521,7 @@ Tips on using, debugging, and developing the compiler can be found at
.SH COPYRIGHT
.nf
Copyright \(co 2002\-2011 Stephen Williams
Copyright \(co 2002\-2014 Stephen Williams
This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -141,6 +141,8 @@ char warning_flags[16] = "n";
unsigned integer_width = 32;
unsigned width_cap = 65536;
char*mod_list = 0;
char*command_filename = 0;
@ -1192,6 +1194,8 @@ int main(int argc, char **argv)
fprintf(iconfig_file, "iwidth:%u\n", integer_width);
fprintf(iconfig_file, "widthcap:%u\n", width_cap);
/* Write the preprocessor command needed to preprocess a
single file. This may be used to preprocess library
files. */

View File

@ -756,12 +756,11 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
r_val = rc->value().as_long();
// Clip to a sensible range to avoid underflow/overflow
// in the following calculations. 1024 bits should be
// enough for anyone...
// in the following calculations.
if (r_val < 0)
r_val = 0;
if (r_val > 1024)
r_val = 1024;
if (r_val > width_cap)
r_val = width_cap;
// If the left operand is a simple unsized number, we
// can calculate the actual width required for the power

10
main.cc
View File

@ -1,5 +1,5 @@
const char COPYRIGHT[] =
"Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)";
"Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)";
/*
* This source code is free software; you can redistribute it
@ -191,6 +191,11 @@ bool verbose_flag = false;
unsigned integer_width = 32;
/*
* Width limit for unsized expressions.
*/
unsigned width_cap = 65536;
int def_ts_units = 0;
int def_ts_prec = 0;
@ -647,6 +652,9 @@ static void read_iconfig_file(const char*ipath)
} else if (strcmp(buf, "iwidth") == 0) {
integer_width = strtoul(cp,0,10);
} else if (strcmp(buf, "widthcap") == 0) {
width_cap = strtoul(cp,0,10);
} else if (strcmp(buf, "library_file") == 0) {
perm_string path = filename_strings.make(cp);
library_file_map[path] = true;

View File

@ -746,9 +746,9 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
// If context_width is positive, this is the RHS of an assignment,
// so the LHS width must also be included in the width calculation.
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
&& (expr_width < (unsigned)context_width))
expr_width = context_width;
unsigned pos_context_width = context_width > 0 ? context_width : 0;
if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width))
expr_width = pos_context_width;
if (debug_elaborate) {
cerr << pe->get_fileline() << ": elab_and_eval: test_width of "
@ -765,8 +765,8 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
// If we can get the same result using a smaller expression
// width, do so.
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
&& (expr_width > (unsigned)context_width)) {
expr_width = max(pe->min_width(), (unsigned)context_width);
&& (expr_width > pos_context_width)) {
expr_width = max(pe->min_width(), pos_context_width);
if (debug_elaborate) {
cerr << pe->get_fileline() << ": "
@ -774,6 +774,15 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
}
}
if ((mode >= PExpr::LOSSLESS) && (expr_width > width_cap)
&& (expr_width > pos_context_width)) {
cerr << pe->get_fileline() << ": warning: excessive unsized "
<< "expression width detected." << endl;
cerr << pe->get_fileline() << ": : The expression width "
<< "is capped at " << width_cap << " bits." << endl;
expr_width = width_cap;
}
unsigned flags = PExpr::NO_FLAGS;
if (need_const)
flags |= PExpr::NEED_CONST;
@ -789,10 +798,10 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
tmp = cast_to_real(tmp);
break;
case IVL_VT_BOOL:
tmp = cast_to_int2(tmp, context_width > 0 ? context_width : 0);
tmp = cast_to_int2(tmp, pos_context_width);
break;
case IVL_VT_LOGIC:
tmp = cast_to_int4(tmp, context_width > 0 ? context_width : 0);
tmp = cast_to_int4(tmp, pos_context_width);
break;
default:
break;