+2011-05-21 Paul Eggert <eggert@cs.ucla.edu>
+
+ * data.c: Avoid integer truncation in expressions involving floats.
+ * data.c: Include <intprops.h>.
+ (arith_driver): When there's an integer overflow in an expression
+ involving floating point, convert the integers to floating point
+ so that the resulting value does not suffer from catastrophic
+ integer truncation. For example, on a 64-bit host (* 4
+ most-negative-fixnum 0.5) should yield about -4.6e+18, not zero.
+ Do not rely on undefined behavior after integer overflow.
+
2011-05-20 Paul Eggert <eggert@cs.ucla.edu>
merge count_size_as_multibyte, parse_str_to_multibyte
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
+
+#include <intprops.h>
+
#include "lisp.h"
#include "puresize.h"
#include "character.h"
register EMACS_INT accum = 0;
register EMACS_INT next;
+ int overflow = 0;
+ size_t ok_args;
+ EMACS_INT ok_accum;
+
switch (SWITCH_ENUM_CAST (code))
{
case Alogior:
for (argnum = 0; argnum < nargs; argnum++)
{
+ if (! overflow)
+ {
+ ok_args = argnum;
+ ok_accum = accum;
+ }
+
/* Using args[argnum] as argument to CHECK_NUMBER_... */
val = args[argnum];
CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val);
if (FLOATP (val))
- return float_arith_driver ((double) accum, argnum, code,
+ return float_arith_driver (ok_accum, ok_args, code,
nargs, args);
args[argnum] = val;
next = XINT (args[argnum]);
switch (SWITCH_ENUM_CAST (code))
{
case Aadd:
+ if (INT_ADD_OVERFLOW (accum, next))
+ {
+ overflow = 1;
+ accum &= INTMASK;
+ }
accum += next;
break;
case Asub:
+ if (INT_SUBTRACT_OVERFLOW (accum, next))
+ {
+ overflow = 1;
+ accum &= INTMASK;
+ }
accum = argnum ? accum - next : nargs == 1 ? - next : next;
break;
case Amult:
- accum *= next;
+ if (INT_MULTIPLY_OVERFLOW (accum, next))
+ {
+ overflow = 1;
+ accum = (EMACS_UINT) accum * (EMACS_UINT) next & INTMASK;
+ }
+ else
+ accum *= next;
break;
case Adiv:
if (!argnum)
}
}
+ accum &= INTMASK;
+ if (MOST_POSITIVE_FIXNUM < accum)
+ accum += MOST_NEGATIVE_FIXNUM - (MOST_POSITIVE_FIXNUM + 1);
XSETINT (val, accum);
return val;
}