[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

branch-1_4 coredump on x86 eval

From: Eric Blake
Subject: branch-1_4 coredump on x86 eval
Date: Tue, 27 Jun 2006 07:30:54 -0600
User-agent: Thunderbird (Windows/20060516)

Hash: SHA1

On x86 architecture:
$ echo 'eval((1<<31)/-1)'|m4
Floating point exception (core dumped)

Fixed as shown below.

Meanwhile, should 1.4.5 change the eval operator precedence to match C, or
leave it alone?  As an example of where GNU and traditional Solaris go
wrong, but Solaris xpg4 matches POSIX:
$ echo 'eval(!0*2)'|m4
$ echo 'eval(!0*2)'|/usr/ccs/bin/m4
$ echo 'eval(!0*2)'|/usr/xpg4/bin/m4

2006-06-27  Eric Blake  <address@hidden>

        * doc/m4.texinfo (Eval): Document 32-bit signed limitations
        required by POSIX, and add example that exposed core dump on x86
        (Incompatibilities): Document incompatibility in eval precedence.
        * src/eval.c (shift_term): Explicitly mask, to avoid undefined
        (mult_term): Explicitly check for -1, to avoid SIGFPE on x86.
        * NEWS: Document this change.

- --
Life is short - so eat dessert first!

Eric Blake             address@hidden
Version: GnuPG v1.4.2.1 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

Index: NEWS
RCS file: /sources/m4/m4/NEWS,v
retrieving revision
diff -u -p -r1. NEWS
--- NEWS        23 Jun 2006 12:58:20 -0000
+++ NEWS        27 Jun 2006 13:11:27 -0000
@@ -16,6 +16,8 @@ Version 1.4.5 - ?? 2006, by ???  (CVS ve
   This allows downgrading from beta m4-1.4o to m4-1.4.5 without breaking
 * The format and indir macros are now recognized only with arguments.
+* The eval macro no longer crashes on x86 architectures when dividing the
+  minimum integer by -1.
 Version 1.4.4b - 17 June 2006, by Eric Blake  (CVS version 1.4.4a)
Index: doc/m4.texinfo
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision
diff -u -p -r1. m4.texinfo
--- doc/m4.texinfo      27 Jun 2006 12:49:52 -0000
+++ doc/m4.texinfo      27 Jun 2006 13:11:28 -0000
@@ -3064,8 +3064,8 @@ Expressions can contain the following op
 decreasing precedence.
 @table @code
address@hidden -
-Unary minus
address@hidden + -
+Unary plus and minus
 @item **
 @item *  /  %
@@ -3094,10 +3094,14 @@ Logical or
 All operators, except exponentiation, are left associative.
-Note that many @code{m4} implementations use @samp{^} as an alternate
-operator for the exponentiation, while many others use @samp{^} for the
-bitwise exclusive-or.  GNU @code{m4} changed its behavior: it used to
-exponentiate for @samp{^}, it now computes the bitwise exclusive-or.
+Note that some older @code{m4} implementations use @samp{^} as an
+alternate operator for exponentiation, although @acronym{POSIX} requires
+the C behavior of bitwise exclusive-or.  On the other hand, the
+precedence of @samp{~} and @samp{!} are different in GNU @code{m4} than
+they are in C, matching the precedence in traditional @code{m4}
+implementations.  This behavior is likely to change in a future
+version to match @acronym{POSIX}, so use parentheses to force the
+desired precedence.
 Numbers without special prefix are given decimal.  A simple @samp{0}
 prefix introduces an octal number.  @samp{0x} introduces a hexadecimal
@@ -3140,6 +3144,24 @@ names, even if they expand to a valid ex
 expression).  Therefore all macros must be expanded before they are
 passed to @code{eval}.
+All evaluation is done with 32-bit signed integers, assuming
+2's-complement with wrap-around.  The shift operators are defined in GNU
address@hidden by doing an implicit bit-wise and of the right-hand operand
+with 0x1f, and sign-extension with right shift.
+eval(0x80000000 / -1)
+eval(0x80000000 % -1)
+eval(-4 >> 33)
address@hidden example
 If @var{radix} is specified, it specifies the radix to be used in the
 expansion.  The default radix is 10.  The result of @code{eval} is
 always taken to be signed.  The @var{width} argument specifies a minimum
@@ -3790,6 +3812,18 @@ processing, to span file boundaries.  Th
 @samp{len(}, and @file{b.m4} contains @samp{abc)}, @kbd{m4 a.m4 b.m4}
 outputs @samp{3} with traditional @code{m4}, but gives an error message
 that the end of file was encountered inside a macro with GNU @code{m4}.
address@hidden requires @code{eval} (@pxref{Eval}) to treat all
+operators with the same precedence as C.  However, GNU @code{m4}
+currently follows the traditional precedence of other @code{m4}
+implementations, where bitwise and logical negation (@samp{~} and
address@hidden) have lower precedence than equality operators, rather than
+equal precedence with other unary operators.  Use explicit parentheses
+to ensure proper precedence.  As extensions to @acronym{POSIX}, GNU
address@hidden treats the shift operators @samp{<<} and @samp{>>} as
+well-defined on signed integers (even though they are not in C), and
+adds the exponentiation operator @samp{**}.
 @end itemize
 @node Other Incompatibilities,  , Incompatibilities, Compatibility
Index: src/eval.c
RCS file: /sources/m4/m4/src/Attic/eval.c,v
retrieving revision
diff -u -p -r1. eval.c
--- src/eval.c  23 Jun 2006 13:06:10 -0000
+++ src/eval.c  27 Jun 2006 13:11:28 -0000
@@ -22,7 +22,8 @@
 /* This file contains the functions to evaluate integer expressions for
    the "eval" macro.  It is a little, fairly self-contained module, with
    its own scanner, and a recursive descent parser.  The only entry point
-   is evaluate ().  */
+   is evaluate ().  For POSIX semantics of the "eval" macro, the type
+   eval_t must be a 32-bit signed integer.  */
 #include "m4.h"
@@ -151,7 +152,7 @@ eval_lex (eval_t *val)
       (*val) = 0;
       for (; *eval_text; eval_text++)
-          if (isdigit (to_uchar (*eval_text)))
+         if (isdigit (to_uchar (*eval_text)))
            digit = *eval_text - '0';
          else if (islower (to_uchar (*eval_text)))
            digit = *eval_text - 'a' + 10;
@@ -579,14 +580,20 @@ shift_term (eval_token et, eval_t *v1)
       if ((er = add_term (et, &v2)) != NO_ERROR)
        return er;
+      /* Shifting by a negative number, or by greater than the width, is
+        undefined in C, but POSIX requires eval to operate on 32-bit signed
+        numbers.  Explicitly mask the right argument to ensure defined
+        behavior.  */
       switch (op)
        case LSHIFT:
-         *v1 = *v1 << v2;
+         *v1 = *v1 << (v2 & 0x1f);
        case RSHIFT:
-         *v1 = *v1 >> v2;
+         /* This assumes 2's-complement with sign-extension, since shifting
+            a negative number right is implementation-defined in C.  */
+         *v1 = *v1 >> (v2 & 0x1f);
@@ -661,6 +668,9 @@ mult_term (eval_token et, eval_t *v1)
        case DIVIDE:
          if (v2 == 0)
            return DIVIDE_ZERO;
+         else if (v2 == -1)
+           /* Avoid the x86 SIGFPE on INT_MIN / -1.  */
+           *v1 = -*v1;
            *v1 = *v1 / v2;
@@ -668,6 +678,9 @@ mult_term (eval_token et, eval_t *v1)
        case MODULO:
          if (v2 == 0)
            return MODULO_ZERO;
+         else if (v2 == -1)
+           /* Avoid the x86 SIGFPE on INT_MIN % -1.  */
+           *v1 = 0;
            *v1 = *v1 % v2;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]