Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:4479 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 85257 invoked by uid 1010); 14 Sep 2003 17:37:18 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 85209 invoked from network); 14 Sep 2003 17:37:17 -0000 Received: from unknown (HELO mail.zend.com) (192.117.235.230) by pb1.pair.com with SMTP; 14 Sep 2003 17:37:17 -0000 Received: (qmail 10821 invoked from network); 14 Sep 2003 17:37:14 -0000 Received: from localhost (HELO zeev-laptop.zend.com) (127.0.0.1) by localhost with SMTP; 14 Sep 2003 17:37:14 -0000 Reply-To: zeev@zend.com Message-ID: <5.1.0.14.2.20030914203158.0585dfa8@localhost> X-Sender: zeev@localhost X-Mailer: QUALCOMM Windows Eudora Version 5.1 Date: Sun, 14 Sep 2003 20:37:15 +0300 To: Ard Biesheuvel Cc: internals@lists.php.net,Marcus =?iso-8859-1?Q?B=F6rger?= In-Reply-To: <3F633153.5060907@php.net> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; format=flowed Subject: Re: [PHP-DEV] [PATCH] Fix for 64-bit arch errors in zend_operators.c From: zeev@zend.com (Zeev Suraski) References: <3F633153.5060907@php.net> The patch looks good - I committed it. Thanks! Zeev At 18:01 13/09/2003, Ard Biesheuvel wrote: >Hello group, > >Currently, the +, - en * operations in zend_operators in C do their >calculcations on long arguments with doubles, and check if the result >would fit in a long. > >This failed for me on FreeBSD/alpha (in some of the math tests), because >doubles are not accurate enough to represent LONG_MIN or LONG_MAX. This >causes the comparison > >'((double) LONG_MAX) + 1 > (double) LONG_MAX' > >to result in 'false' because they have the same double representation. >Since a lot of tests use LONG_MAX in comparisons, this caused a lot of >them to fail on this architecture. > >One solution could be to use long doubles, but in my opinion it is better >to check the sign bit directly. > >A patch is attached. > >-- >Ard > > > >Index: zend_operators.c >=================================================================== >RCS file: /repository/ZendEngine2/zend_operators.c,v >retrieving revision 1.160 >diff -u -r1.160 zend_operators.c >--- zend_operators.c 17 Aug 2003 19:11:48 -0000 1.160 >+++ zend_operators.c 13 Sep 2003 13:15:30 -0000 >@@ -33,6 +33,8 @@ > #include "ext/bcmath/number.h" > #endif > >+#define LONG_SIGN_MASK (1L << (8*SIZEOF_LONG-1)) >+ > ZEND_API int zend_atoi(const char *str, int str_len) > { > int retval; >@@ -664,13 +666,16 @@ > > > if (op1->type == IS_LONG && op2->type == IS_LONG) { >- double dval = (double) op1->value.lval + (double) >op2->value.lval; >+ long lval = op1->value.lval + op2->value.lval; >+ >+ /* check for overflow by comparing sign bits */ >+ if ( (op1->value.lval & LONG_SIGN_MASK) == >(op2->value.lval & LONG_SIGN_MASK) >+ && (op1->value.lval & LONG_SIGN_MASK) != (lval & >LONG_SIGN_MASK)) { > >- if ((dval > (double) LONG_MAX) || (dval < (double) >LONG_MIN)) { >- result->value.dval = dval; >+ result->value.dval = (double) op1->value.lval + >(double) op2->value.lval; > result->type = IS_DOUBLE; > } else { >- result->value.lval = op1->value.lval + >op2->value.lval; >+ result->value.lval = lval; > result->type = IS_LONG; > } > return SUCCESS; >@@ -701,13 +706,16 @@ > zendi_convert_scalar_to_number(op2, op2_copy, result); > > if (op1->type == IS_LONG && op2->type == IS_LONG) { >- double dval = (double) op1->value.lval - (double) >op2->value.lval; >+ long lval = op1->value.lval - op2->value.lval; >+ >+ /* check for overflow by comparing sign bits */ >+ if ( (op1->value.lval & LONG_SIGN_MASK) != >(op2->value.lval & LONG_SIGN_MASK) >+ && (op1->value.lval & LONG_SIGN_MASK) != (lval & >LONG_SIGN_MASK)) { > >- if ((dval < (double) LONG_MIN) || (dval > (double) >LONG_MAX)) { >- result->value.dval = dval; >+ result->value.dval = (double) op1->value.lval - >(double) op2->value.lval; > result->type = IS_DOUBLE; > } else { >- result->value.lval = op1->value.lval - >op2->value.lval; >+ result->value.lval = lval; > result->type = IS_LONG; > } > return SUCCESS; >@@ -738,13 +746,14 @@ > zendi_convert_scalar_to_number(op2, op2_copy, result); > > if (op1->type == IS_LONG && op2->type == IS_LONG) { >- double dval = (double) op1->value.lval * (double) >op2->value.lval; >- >- if ((dval > (double) LONG_MAX) || (dval < (double) >LONG_MIN)) { >- result->value.dval = dval; >+ long lval = op1->value.lval * op2->value.lval; >+ >+ /* check for overflow by applying the reverse calculation */ >+ if (op1->value.lval != 0 && lval / op1->value.lval != >op2->value.lval) { >+ result->value.dval = (double) op1->value.lval * >(double) op2->value.lval; > result->type = IS_DOUBLE; > } else { >- result->value.lval = op1->value.lval * >op2->value.lval; >+ result->value.lval = lval; > result->type = IS_LONG; > } > return SUCCESS; > >-- >PHP Internals - PHP Runtime Development Mailing List >To unsubscribe, visit: http://www.php.net/unsub.php