Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:8466 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 57955 invoked by uid 1010); 9 Mar 2004 15:50:48 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 57931 invoked by uid 1007); 9 Mar 2004 15:50:48 -0000 Message-ID: <20040309155048.57930.qmail@pb1.pair.com> To: internals@lists.php.net Date: Tue, 09 Mar 2004 16:50:50 +0100 User-Agent: Mozilla Thunderbird 0.5 (Windows/20040207) X-Accept-Language: en-us, en MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------040400060302050004070709" X-Posted-By: 80.126.21.70 Subject: bug in zend_multiply.h From: abies@php.net (Ard Biesheuvel) --------------040400060302050004070709 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit This code fails on 64-bit archs because it relies on the accuracy of a double to be sufficient to represent LONG_MAX. The patch adresses it by checking for overflow by reversing the calculation instead of casting to a double and back to long. #include "build/php5-cvs/Zend/zend_multiply.h" #define LONG_MIN (1L << (8*sizeof(long)-1)) #define LONG_MAX ~LONG_MIN int main() { long res = 0; double d = 0; int overflow; /* obviously (LONG_MAX-1) * 1 can be represented by a long */ ZEND_SIGNED_MULTIPLY_LONG(LONG_MAX-1,1,res,d,overflow); printf("res: %ld/%.4f, %soverflow\n", result, d, overflow?"":"no "); return 0; } -- Ard --------------040400060302050004070709 Content-Type: text/plain; name="mul.diff.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="mul.diff.txt" --- Zend/zend_multiply.h Sun Mar 7 13:59:35 2004 +++ Zend/zend_multiply.h.new Wed Mar 3 09:14:04 2004 @@ -33,13 +33,13 @@ #else #define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \ - double __tmpvar = (double) (a) * (double) (b); \ + long __tmpvar = (a) * (b); \ \ - if (__tmpvar >= LONG_MAX || __tmpvar <= LONG_MIN) { \ - (dval) = __tmpvar; \ + if ((a) != 0 && __tmpvar / (a) != (b)) { \ + (dval) = (double)(a) * (double)(b); \ (usedval) = 1; \ } else { \ - (lval) = (a) * (b); \ + (lval) = __tmpvar; \ (usedval) = 0; \ } \ } while (0) --------------040400060302050004070709--