Commit 4cf8de9f by Richard Stallman

(exp): Detect signed integer overflow.

Replace `(unsigned)' with `(unsigned long)'.  When
evaluating << and >>, compute the correct answer without shifting
by more than HOST_BITS_PER_LONG, or by a negative quantity.
(integer_overflow, left_shift, right_shift): New functions.

From-SVN: r2118
parent 0bbb7f4d
...@@ -98,6 +98,14 @@ extern int traditional; ...@@ -98,6 +98,14 @@ extern int traditional;
#ifndef WCHAR_TYPE_SIZE #ifndef WCHAR_TYPE_SIZE
#define WCHAR_TYPE_SIZE INT_TYPE_SIZE #define WCHAR_TYPE_SIZE INT_TYPE_SIZE
#endif #endif
/* Yield nonzero if adding two numbers with A's and B's signs can yield a
number with SUM's sign, where A, B, and SUM are all C integers. */
#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
static void integer_overflow ();
static long left_shift ();
static long right_shift ();
%} %}
%union { %union {
...@@ -147,6 +155,8 @@ exp1 : exp ...@@ -147,6 +155,8 @@ exp1 : exp
/* Expressions, not including the comma operator. */ /* Expressions, not including the comma operator. */
exp : '-' exp %prec UNARY exp : '-' exp %prec UNARY
{ $$.value = - $2.value; { $$.value = - $2.value;
if (($$.value & $2.value) < 0 && ! $2.unsignedp)
integer_overflow ();
$$.unsignedp = $2.unsignedp; } $$.unsignedp = $2.unsignedp; }
| '!' exp %prec UNARY | '!' exp %prec UNARY
{ $$.value = ! $2.value; { $$.value = ! $2.value;
...@@ -175,9 +185,15 @@ exp : '-' exp %prec UNARY ...@@ -175,9 +185,15 @@ exp : '-' exp %prec UNARY
exp : exp '*' exp exp : exp '*' exp
{ $$.unsignedp = $1.unsignedp || $3.unsignedp; { $$.unsignedp = $1.unsignedp || $3.unsignedp;
if ($$.unsignedp) if ($$.unsignedp)
$$.value = (unsigned) $1.value * $3.value; $$.value = (unsigned long) $1.value * $3.value;
else else
$$.value = $1.value * $3.value; } {
$$.value = $1.value * $3.value;
if ($1.value
&& ($$.value / $1.value != $3.value
|| ($$.value & $1.value & $3.value) < 0))
integer_overflow ();
} }
| exp '/' exp | exp '/' exp
{ if ($3.value == 0) { if ($3.value == 0)
{ {
...@@ -186,9 +202,13 @@ exp : exp '*' exp ...@@ -186,9 +202,13 @@ exp : exp '*' exp
} }
$$.unsignedp = $1.unsignedp || $3.unsignedp; $$.unsignedp = $1.unsignedp || $3.unsignedp;
if ($$.unsignedp) if ($$.unsignedp)
$$.value = (unsigned) $1.value / $3.value; $$.value = (unsigned long) $1.value / $3.value;
else else
$$.value = $1.value / $3.value; } {
$$.value = $1.value / $3.value;
if (($$.value & $1.value & $3.value) < 0)
integer_overflow ();
} }
| exp '%' exp | exp '%' exp
{ if ($3.value == 0) { if ($3.value == 0)
{ {
...@@ -197,27 +217,35 @@ exp : exp '*' exp ...@@ -197,27 +217,35 @@ exp : exp '*' exp
} }
$$.unsignedp = $1.unsignedp || $3.unsignedp; $$.unsignedp = $1.unsignedp || $3.unsignedp;
if ($$.unsignedp) if ($$.unsignedp)
$$.value = (unsigned) $1.value % $3.value; $$.value = (unsigned long) $1.value % $3.value;
else else
$$.value = $1.value % $3.value; } $$.value = $1.value % $3.value; }
| exp '+' exp | exp '+' exp
{ $$.value = $1.value + $3.value; { $$.value = $1.value + $3.value;
$$.unsignedp = $1.unsignedp || $3.unsignedp; } $$.unsignedp = $1.unsignedp || $3.unsignedp;
if (! $$.unsignedp
&& ! possible_sum_sign ($1.value, $3.value,
$$.value))
integer_overflow (); }
| exp '-' exp | exp '-' exp
{ $$.value = $1.value - $3.value; { $$.value = $1.value - $3.value;
$$.unsignedp = $1.unsignedp || $3.unsignedp; } $$.unsignedp = $1.unsignedp || $3.unsignedp;
if (! $$.unsignedp
&& ! possible_sum_sign ($$.value, $3.value,
$1.value))
integer_overflow (); }
| exp LSH exp | exp LSH exp
{ $$.unsignedp = $1.unsignedp; { $$.unsignedp = $1.unsignedp;
if ($$.unsignedp) if ($3.value < 0 && ! $3.unsignedp)
$$.value = (unsigned) $1.value << $3.value; $$.value = right_shift (&$1, -$3.value);
else else
$$.value = $1.value << $3.value; } $$.value = left_shift (&$1, $3.value); }
| exp RSH exp | exp RSH exp
{ $$.unsignedp = $1.unsignedp; { $$.unsignedp = $1.unsignedp;
if ($$.unsignedp) if ($3.value < 0 && ! $3.unsignedp)
$$.value = (unsigned) $1.value >> $3.value; $$.value = left_shift (&$1, -$3.value);
else else
$$.value = $1.value >> $3.value; } $$.value = right_shift (&$1, $3.value); }
| exp EQUAL exp | exp EQUAL exp
{ $$.value = ($1.value == $3.value); { $$.value = ($1.value == $3.value);
$$.unsignedp = 0; } $$.unsignedp = 0; }
...@@ -227,25 +255,25 @@ exp : exp '*' exp ...@@ -227,25 +255,25 @@ exp : exp '*' exp
| exp LEQ exp | exp LEQ exp
{ $$.unsignedp = 0; { $$.unsignedp = 0;
if ($1.unsignedp || $3.unsignedp) if ($1.unsignedp || $3.unsignedp)
$$.value = (unsigned) $1.value <= $3.value; $$.value = (unsigned long) $1.value <= $3.value;
else else
$$.value = $1.value <= $3.value; } $$.value = $1.value <= $3.value; }
| exp GEQ exp | exp GEQ exp
{ $$.unsignedp = 0; { $$.unsignedp = 0;
if ($1.unsignedp || $3.unsignedp) if ($1.unsignedp || $3.unsignedp)
$$.value = (unsigned) $1.value >= $3.value; $$.value = (unsigned long) $1.value >= $3.value;
else else
$$.value = $1.value >= $3.value; } $$.value = $1.value >= $3.value; }
| exp '<' exp | exp '<' exp
{ $$.unsignedp = 0; { $$.unsignedp = 0;
if ($1.unsignedp || $3.unsignedp) if ($1.unsignedp || $3.unsignedp)
$$.value = (unsigned) $1.value < $3.value; $$.value = (unsigned long) $1.value < $3.value;
else else
$$.value = $1.value < $3.value; } $$.value = $1.value < $3.value; }
| exp '>' exp | exp '>' exp
{ $$.unsignedp = 0; { $$.unsignedp = 0;
if ($1.unsignedp || $3.unsignedp) if ($1.unsignedp || $3.unsignedp)
$$.value = (unsigned) $1.value > $3.value; $$.value = (unsigned long) $1.value > $3.value;
else else
$$.value = $1.value > $3.value; } $$.value = $1.value > $3.value; }
| exp '&' exp | exp '&' exp
...@@ -548,10 +576,10 @@ yylex () ...@@ -548,10 +576,10 @@ yylex ()
if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1) if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1)
|| ((result >> (num_bits - 1)) & 1) == 0) || ((result >> (num_bits - 1)) & 1) == 0)
yylval.integer.value yylval.integer.value
= result & ((unsigned) ~0 >> (HOST_BITS_PER_INT - num_bits)); = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
else else
yylval.integer.value yylval.integer.value
= result | ~((unsigned) ~0 >> (HOST_BITS_PER_INT - num_bits)); = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
} }
else else
{ {
...@@ -785,6 +813,47 @@ yyerror (s) ...@@ -785,6 +813,47 @@ yyerror (s)
error (s); error (s);
longjmp (parse_return_error, 1); longjmp (parse_return_error, 1);
} }
static void
integer_overflow ()
{
pedwarn ("integer overflow in preprocessor expression");
}
static long
left_shift (a, b)
struct constant *a;
unsigned long b;
{
if (b >= HOST_BITS_PER_LONG)
{
if (! a->unsignedp && a->value != 0)
integer_overflow ();
return 0;
}
else if (a->unsignedp)
return (unsigned long) a->value << b;
else
{
long l = a->value << b;
if (l >> b != a->value)
integer_overflow ();
return l;
}
}
static long
right_shift (a, b)
struct constant *a;
unsigned long b;
{
if (b >= HOST_BITS_PER_LONG)
return a->unsignedp ? 0 : a->value >> (HOST_BITS_PER_LONG - 1);
else if (a->unsignedp)
return (unsigned long) a->value >> b;
else
return a->value >> b;
}
/* This page contains the entry point to this file. */ /* This page contains the entry point to this file. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment