[exim-cvs] INT_MIN {/,%} -1 = INT_MAX for our purposes.

Kezdőlap
Üzenet törlése
Válasz az üzenetre
Szerző: Exim Git Commits Mailing List
Dátum:  
Címzett: exim-cvs
Tárgy: [exim-cvs] INT_MIN {/,%} -1 = INT_MAX for our purposes.
Gitweb: http://git.exim.org/exim.git/commitdiff/053a9aa35c76fe12f456b508fc9d96aa9a78e6c5
Commit:     053a9aa35c76fe12f456b508fc9d96aa9a78e6c5
Parent:     5fa5f96fcfb9aa3c73e4ce9289a30be1e616e576
Author:     Phil Pennock <pdp@???>
AuthorDate: Sun May 8 03:11:09 2011 -0400
Committer:  Phil Pennock <pdp@???>
CommitDate: Sun May 8 22:54:29 2011 -0400


    INT_MIN {/,%} -1 = INT_MAX for our purposes.


    Dodge a SIGFPE on x86.
---
 src/src/expand.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)


diff --git a/src/src/expand.c b/src/src/expand.c
index 2e59c40..d1b8167 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -3106,6 +3106,32 @@ if (*error == NULL)
     int op = *s++;
     int y = eval_op_unary(&s, decimal, error);
     if (*error != NULL) break;
+    /* SIGFPE both on div/mod by zero and on INT_MIN / -1, which would give
+     * a value of INT_MAX+1. Note that INT_MIN * -1 gives INT_MIN for me, which
+     * is a bug somewhere in [gcc 4.2.1, FreeBSD, amd64].  In fact, -N*-M where
+     * -N*M is INT_MIN will yielf INT_MIN.
+     * Since we don't support floating point, this is somewhat simpler.
+     * Ideally, we'd return an error, but since we overflow for all other
+     * arithmetic, consistency suggests otherwise, but what's the correct value
+     * to use?  There is none.
+     * The C standard guarantees overflow for unsigned arithmetic but signed
+     * overflow invokes undefined behaviour; in practice, this is overflow
+     * except for converting INT_MIN to INT_MAX+1.  We also can't guarantee
+     * that long/longlong larger than int are available, or we could just work
+     * with larger types.  We should consider whether to guarantee 32bit eval
+     * and 64-bit working variables, with errors returned.  For now ...
+     * So, the only SIGFPEs occur with a non-shrinking div/mod, thus -1; we
+     * can just let the other invalid results occur otherwise, as they have
+     * until now.  For this one case, we can coerce.
+     */
+    if (y == -1 && x == INT_MIN && op != '*')
+      {
+      DEBUG(D_expand)
+        debug_printf("Integer exception dodging: %d%c-1 coerced to %d\n",
+            INT_MIN, op, INT_MAX);
+      x = INT_MAX;
+      continue;
+      }
     if (op == '*')
       x *= y;
     else