m4-patches
[Top][All Lists]
Advanced

[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 1.5.0.4 (Windows/20060516)

-----BEGIN PGP SIGNED MESSAGE-----
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
1
$ echo 'eval(!0*2)'|/usr/ccs/bin/m4
1
$ echo 'eval(!0*2)'|/usr/xpg4/bin/m4
2

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
        architectures.
        (Incompatibilities): Document incompatibility in eval precedence.
        * src/eval.c (shift_term): Explicitly mask, to avoid undefined
        behavior.
        (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
-----BEGIN PGP SIGNATURE-----
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

iD8DBQFEoTMO84KuGfSFAYARAgUhAKCO2e295DJVO7rtqkjdV18QJTshNACgi2sa
jBYWIC7BXkypFVPCglG2gR0=
=QRJZ
-----END PGP SIGNATURE-----
Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.1.1.1.2.25
diff -u -p -r1.1.1.1.2.25 NEWS
--- NEWS        23 Jun 2006 12:58:20 -0000      1.1.1.1.2.25
+++ 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
   autoconf.
 * 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 1.1.1.1.2.25
diff -u -p -r1.1.1.1.2.25 m4.texinfo
--- doc/m4.texinfo      27 Jun 2006 12:49:52 -0000      1.1.1.1.2.25
+++ 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 **
 Exponentiation
 @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.
+
address@hidden
+eval(0x80000000 / -1)
address@hidden
+eval(0x80000000 % -1)
address@hidden
+eval(0x7fffffff)
address@hidden
+incr(eval(0x7fffffff))
address@hidden
+eval(-4 >> 33)
address@hidden
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
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 1.1.1.1.2.3
diff -u -p -r1.1.1.1.2.3 eval.c
--- src/eval.c  23 Jun 2006 13:06:10 -0000      1.1.1.1.2.3
+++ 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);
          break;
 
        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);
          break;
 
        default:
@@ -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;
          else
            *v1 = *v1 / v2;
          break;
@@ -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;
          else
            *v1 = *v1 % v2;
          break;

reply via email to

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