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 #ifndef __compiler_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -36,6 +36,11 @@
*/ */
extern unsigned integer_width; 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 * This is the maximum number of recursive module loops allowed within
* a generate block. * 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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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; } "+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. */ /* If it is not any known plus-flag, return the generic form. */
"+"[^\n \t\b\f\r+]* { "+"[^\n \t\b\f\r+]* {
cflval.text = strdup(yytext); 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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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_Da TOK_Dc TOK_Dv TOK_Dy
%token TOK_DEFINE TOK_INCDIR TOK_INTEGER_WIDTH TOK_LIBDIR TOK_LIBDIR_NOCASE %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_LIBEXT TOK_PARAMETER TOK_TIMESCALE TOK_VHDL_WORK TOK_VHDL_LIBDIR
%token TOK_WIDTH_CAP
%token <text> TOK_PLUSARG TOK_PLUSWORD TOK_STRING %token <text> TOK_PLUSARG TOK_PLUSWORD TOK_STRING
%% %%
@ -191,6 +192,13 @@ item
free(tmp); 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 /* The +<word> tokens that are not otherwise matched, are
ignored. The skip_args rule arranges for all the argument words ignored. The skip_args rule arranges for all the argument words
to be consumed. */ to be consumed. */

View File

@ -1,7 +1,7 @@
#ifndef __globals_H #ifndef __globals_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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. */ /* This is the integer-width argument that will be passed to ivl. */
extern unsigned integer_width; 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_work;
extern const char**vhdlpp_libdir; extern const char**vhdlpp_libdir;
extern unsigned vhdlpp_libdir_cnt; 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 .SH NAME
iverilog - Icarus Verilog compiler 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 in the Verilog source. The default is 32, the value can be any desired
integer value. 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" .SH "VARIABLES IN COMMAND FILES"
In certain cases, iverilog supports variables in command files. These 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 .SH COPYRIGHT
.nf .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 This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0 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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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 integer_width = 32;
unsigned width_cap = 65536;
char*mod_list = 0; char*mod_list = 0;
char*command_filename = 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, "iwidth:%u\n", integer_width);
fprintf(iconfig_file, "widthcap:%u\n", width_cap);
/* Write the preprocessor command needed to preprocess a /* Write the preprocessor command needed to preprocess a
single file. This may be used to preprocess library single file. This may be used to preprocess library
files. */ 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(); r_val = rc->value().as_long();
// Clip to a sensible range to avoid underflow/overflow // Clip to a sensible range to avoid underflow/overflow
// in the following calculations. 1024 bits should be // in the following calculations.
// enough for anyone...
if (r_val < 0) if (r_val < 0)
r_val = 0; r_val = 0;
if (r_val > 1024) if (r_val > width_cap)
r_val = 1024; r_val = width_cap;
// If the left operand is a simple unsized number, we // If the left operand is a simple unsized number, we
// can calculate the actual width required for the power // can calculate the actual width required for the power

10
main.cc
View File

@ -1,5 +1,5 @@
const char COPYRIGHT[] = 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 * This source code is free software; you can redistribute it
@ -191,6 +191,11 @@ bool verbose_flag = false;
unsigned integer_width = 32; unsigned integer_width = 32;
/*
* Width limit for unsized expressions.
*/
unsigned width_cap = 65536;
int def_ts_units = 0; int def_ts_units = 0;
int def_ts_prec = 0; int def_ts_prec = 0;
@ -647,6 +652,9 @@ static void read_iconfig_file(const char*ipath)
} else if (strcmp(buf, "iwidth") == 0) { } else if (strcmp(buf, "iwidth") == 0) {
integer_width = strtoul(cp,0,10); 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) { } else if (strcmp(buf, "library_file") == 0) {
perm_string path = filename_strings.make(cp); perm_string path = filename_strings.make(cp);
library_file_map[path] = true; 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, // If context_width is positive, this is the RHS of an assignment,
// so the LHS width must also be included in the width calculation. // so the LHS width must also be included in the width calculation.
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL) unsigned pos_context_width = context_width > 0 ? context_width : 0;
&& (expr_width < (unsigned)context_width)) if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width))
expr_width = context_width; expr_width = pos_context_width;
if (debug_elaborate) { if (debug_elaborate) {
cerr << pe->get_fileline() << ": elab_and_eval: test_width of " 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 // If we can get the same result using a smaller expression
// width, do so. // width, do so.
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL) if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
&& (expr_width > (unsigned)context_width)) { && (expr_width > pos_context_width)) {
expr_width = max(pe->min_width(), (unsigned)context_width); expr_width = max(pe->min_width(), pos_context_width);
if (debug_elaborate) { if (debug_elaborate) {
cerr << pe->get_fileline() << ": " 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; unsigned flags = PExpr::NO_FLAGS;
if (need_const) if (need_const)
flags |= PExpr::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); tmp = cast_to_real(tmp);
break; break;
case IVL_VT_BOOL: case IVL_VT_BOOL:
tmp = cast_to_int2(tmp, context_width > 0 ? context_width : 0); tmp = cast_to_int2(tmp, pos_context_width);
break; break;
case IVL_VT_LOGIC: case IVL_VT_LOGIC:
tmp = cast_to_int4(tmp, context_width > 0 ? context_width : 0); tmp = cast_to_int4(tmp, pos_context_width);
break; break;
default: default:
break; break;