And yet again for expr :-).

$ expr -2147483648 / -1
Floating point exception (core dumped)

expr on Linux (GNU or whatever it is) reports "Numerical result out of
range" for this. But it does the same for other overflows (such as "expr
-9223372036854775808 - 1" on a 64-bit platform) where we just go
ahead. So I don't see why we need to follow it. I don't see anything
specified in SUSv3 at least.


Index: expr.c
===================================================================
RCS file: /cvs/src/bin/expr/expr.c,v
retrieving revision 1.17
diff -u -p -r1.17 expr.c
--- expr.c      21 Jun 2006 18:28:24 -0000      1.17
+++ expr.c      27 Mar 2013 23:45:42 -0000
@@ -9,6 +9,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 #include <locale.h>
 #include <ctype.h>
 #include <regex.h>
@@ -329,9 +330,13 @@ eval4(void)
                                errx(2, "division by zero");
                        }
                        if (op == DIV) {
-                               l->u.i /= r->u.i;
+                               if (l->u.i != INT_MIN || r->u.i != -1)
+                                       l->u.i /= r->u.i;
                        } else {
-                               l->u.i %= r->u.i;
+                               if (l->u.i != INT_MIN || r->u.i != -1)
+                                       l->u.i %= r->u.i;
+                               else
+                                       l->u.i = 0;
                        }
                }
 


On Wed, Mar 27, 2013 at 11:26:23PM +0000, Nicholas Marriott wrote:
> And the same for csh (@ x = -2147483648 % -1):
> 
> Index: exp.c
> ===================================================================
> RCS file: /cvs/src/bin/csh/exp.c,v
> retrieving revision 1.9
> diff -u -p -r1.9 exp.c
> --- exp.c     20 Jul 2010 02:13:10 -0000      1.9
> +++ exp.c     27 Mar 2013 23:23:48 -0000
> @@ -32,6 +32,7 @@
>  
>  #include <sys/types.h>
>  #include <sys/stat.h>
> +#include <limits.h>
>  #include <stdlib.h>
>  #include <unistd.h>
>  #ifndef SHORT_STRINGS
> @@ -346,7 +347,7 @@ static Char *
>  exp5(Char ***vp, bool ignore)
>  {
>      Char *p1, *p2;
> -    int i = 0;
> +    int i = 0, l;
>  
>      p1 = exp6(vp, ignore);
>  #ifdef EDEBUG
> @@ -370,14 +371,22 @@ exp5(Char ***vp, bool ignore)
>               i = egetn(p2);
>               if (i == 0)
>                   stderror(ERR_DIV0);
> -             i = egetn(p1) / i;
> +             l = egetn(p1);
> +             if (l == INT_MIN && i == -1)
> +                     i = INT_MIN;
> +             else
> +                     i = l / i;
>               break;
>  
>           case '%':
>               i = egetn(p2);
>               if (i == 0)
>                   stderror(ERR_MOD0);
> -             i = egetn(p1) % i;
> +             l = egetn(p1);
> +             if (l == INT_MIN && i == -1)
> +                     i = 0;
> +             else
> +                     i = l % i;
>               break;
>           }
>       xfree((ptr_t) p1);
> 
> 
> 
> On Wed, Mar 27, 2013 at 11:15:44PM +0000, Nicholas Marriott wrote:
> > Sure, that actually looks to be what other shells do anyhow.
> > 
> > Index: expr.c
> > ===================================================================
> > RCS file: /cvs/src/bin/ksh/expr.c,v
> > retrieving revision 1.21
> > diff -u -p -r1.21 expr.c
> > --- expr.c  1 Jun 2009 19:00:57 -0000       1.21
> > +++ expr.c  27 Mar 2013 23:13:44 -0000
> > @@ -341,11 +341,17 @@ evalexpr(Expr_state *es, enum prec prec)
> >                     break;
> >             case O_DIV:
> >             case O_DIVASN:
> > -                   res = vl->val.i / vr->val.i;
> > +                   if (vl->val.i == LONG_MIN && vr->val.i == -1)
> > +                           res = LONG_MIN;
> > +                   else
> > +                           res = vl->val.i / vr->val.i;
> >                     break;
> >             case O_MOD:
> >             case O_MODASN:
> > -                   res = vl->val.i % vr->val.i;
> > +                   if (vl->val.i == LONG_MIN && vr->val.i == -1)
> > +                           res = 0;
> > +                   else
> > +                           res = vl->val.i % vr->val.i;
> >                     break;
> >             case O_PLUS:
> >             case O_PLUSASN:
> > 
> > 
> > On Wed, Mar 27, 2013 at 04:06:22PM -0700, Matthew Dempsky wrote:
> > > On Wed, Mar 27, 2013 at 3:56 PM, Nicholas Marriott
> > > <nicholas.marri...@gmail.com> wrote:
> > > >                 case O_DIV:
> > > >                 case O_DIVASN:
> > > > +                       if (vl->val.i == LONG_MIN && vr->val.i == -1)
> > > > +                               evalerr(es, ET_STR, "can't represent 
> > > > result");
> > > >                         res = vl->val.i / vr->val.i;
> > > >                         break;
> > > 
> > > I think LONG_MIN / -1 should still be LONG_MIN.  We don't give errors
> > > for other overflow conditions.

Reply via email to