summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend_API.c32
-rw-r--r--Zend/zend_API.h27
-rw-r--r--Zend/zend_operators.h12
3 files changed, 46 insertions, 25 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 2e13f3a20e..788da61474 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -404,14 +404,16 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
if ((type = is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), p, &d, -1)) == 0) {
return "long";
} else if (type == IS_DOUBLE) {
- if (c == 'L') {
- if (d > ZEND_LONG_MAX) {
- *p = ZEND_LONG_MAX;
- break;
- } else if (d < ZEND_LONG_MIN) {
- *p = ZEND_LONG_MIN;
- break;
+ if (zend_isnan(d)) {
+ return "long";
+ }
+ if (!ZEND_DOUBLE_FITS_LONG(d)) {
+ if (c == 'L') {
+ *p = (d > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
+ } else {
+ return "long";
}
+ break;
}
*p = zend_dval_to_lval(d);
@@ -420,14 +422,16 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
break;
case IS_DOUBLE:
- if (c == 'L') {
- if (Z_DVAL_P(arg) > ZEND_LONG_MAX) {
- *p = ZEND_LONG_MAX;
- break;
- } else if (Z_DVAL_P(arg) < ZEND_LONG_MIN) {
- *p = ZEND_LONG_MIN;
- break;
+ if (zend_isnan(Z_DVAL_P(arg))) {
+ return "long";
+ }
+ if (!ZEND_DOUBLE_FITS_LONG(Z_DVAL_P(arg))) {
+ if (c == 'L') {
+ *p = (Z_DVAL_P(arg) > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
+ } else {
+ return "long";
}
+ break;
}
case IS_NULL:
case IS_FALSE:
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index 052214140f..1e031ca844 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -1064,10 +1064,16 @@ static zend_always_inline int _z_param_long(zval *arg, zend_long *dest, zend_boo
if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
*dest = Z_LVAL_P(arg);
} else if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
- if (strict && UNEXPECTED(Z_DVAL_P(arg) > ZEND_LONG_MAX)) {
- *dest = ZEND_LONG_MAX;
- } else if (strict && UNEXPECTED(Z_DVAL_P(arg) < ZEND_LONG_MIN)) {
- *dest = ZEND_LONG_MIN;
+ if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) {
+ return 0;
+ }
+ if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(Z_DVAL_P(arg)))) {
+ /* Ironically, the strict parameter makes zpp *non*-strict here */
+ if (strict) {
+ *dest = (Z_DVAL_P(arg) > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
+ } else {
+ return 0;
+ }
} else {
*dest = zend_dval_to_lval(Z_DVAL_P(arg));
}
@@ -1077,10 +1083,15 @@ static zend_always_inline int _z_param_long(zval *arg, zend_long *dest, zend_boo
if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) {
if (EXPECTED(type != 0)) {
- if (strict && UNEXPECTED(d > ZEND_LONG_MAX)) {
- *dest = ZEND_LONG_MAX;
- } else if (strict && UNEXPECTED(d < ZEND_LONG_MIN)) {
- *dest = ZEND_LONG_MIN;
+ if (UNEXPECTED(zend_isnan(d))) {
+ return 0;
+ }
+ if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(d))) {
+ if (strict) {
+ *dest = (d > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
+ } else {
+ return 0;
+ }
} else {
*dest = zend_dval_to_lval(d);
}
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index ccd00b4e52..d27f5bf6f6 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -89,6 +89,13 @@ ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_l
END_EXTERN_C()
+#if SIZEOF_ZEND_LONG == 4
+# define ZEND_DOUBLE_FITS_LONG(d) (!((d) > ZEND_LONG_MAX || (d) < ZEND_LONG_MIN))
+#else
+ /* >= as (double)ZEND_LONG_MAX is outside signed range */
+# define ZEND_DOUBLE_FITS_LONG(d) (!((d) >= ZEND_LONG_MAX || (d) < ZEND_LONG_MIN))
+#endif
+
#if ZEND_DVAL_TO_LVAL_CAST_OK
static zend_always_inline zend_long zend_dval_to_lval(double d)
{
@@ -103,7 +110,7 @@ static zend_always_inline zend_long zend_dval_to_lval(double d)
{
if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
return 0;
- } else if (d > ZEND_LONG_MAX || d < ZEND_LONG_MIN) {
+ } else if (!ZEND_DOUBLE_FITS_LONG(d)) {
double two_pow_32 = pow(2., 32.),
dmod;
@@ -122,8 +129,7 @@ static zend_always_inline zend_long zend_dval_to_lval(double d)
{
if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
return 0;
- /* >= as (double)ZEND_LONG_MAX is outside signed range */
- } else if (d >= ZEND_LONG_MAX || d < ZEND_LONG_MIN) {
+ } else if (!ZEND_DOUBLE_FITS_LONG(d)) {
double two_pow_64 = pow(2., 64.),
dmod;