summaryrefslogtreecommitdiff
path: root/Zend/zend_operators.c
diff options
context:
space:
mode:
authorZeev Suraski <zeev@php.net>2003-09-14 17:37:01 +0000
committerZeev Suraski <zeev@php.net>2003-09-14 17:37:01 +0000
commite0508c13bb6a223fcd96985909cdc91c307462fc (patch)
tree43f041725c3da93ad83d8a85395ee44c721ef001 /Zend/zend_operators.c
parenta5d829f9281b31ee6117826f49d57ba0dc5df886 (diff)
downloadphp-git-e0508c13bb6a223fcd96985909cdc91c307462fc.tar.gz
Commit 64-bit fixes to the standard operators
by Ard Biesheuvel (abies@php.net)
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r--Zend/zend_operators.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index 63412b624f..4369f10d90 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -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 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
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 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
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 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
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;