-----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  <[EMAIL PROTECTED]>

        * 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             [EMAIL PROTECTED]
-----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
[EMAIL PROTECTED] -
-Unary minus
[EMAIL PROTECTED] + -
+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
[EMAIL PROTECTED] by doing an implicit bit-wise and of the right-hand operand
+with 0x1f, and sign-extension with right shift.
+
[EMAIL PROTECTED]
+eval(0x80000000 / -1)
[EMAIL PROTECTED]
+eval(0x80000000 % -1)
[EMAIL PROTECTED]
+eval(0x7fffffff)
[EMAIL PROTECTED]
+incr(eval(0x7fffffff))
[EMAIL PROTECTED]
+eval(-4 >> 33)
[EMAIL PROTECTED]
[EMAIL PROTECTED] 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}.
+
[EMAIL PROTECTED]
[EMAIL PROTECTED] 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
[EMAIL PROTECTED]) 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
[EMAIL PROTECTED] 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;
_______________________________________________
M4-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/m4-patches

Reply via email to