Re: [PATCH] Fix for 64-bit arch errors in zend_operators.c
| From: | Zeev Suraski | Date: | Sun, 14 Sep 2003 17:37:15 +0000 |
| Subject: | Re: [PATCH] Fix for 64-bit arch errors in zend_operators.c | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-4479@lists.php.net to get a copy of this message | ||
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