diff options
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/zend_API.c | 32 | ||||
-rw-r--r-- | Zend/zend_API.h | 27 | ||||
-rw-r--r-- | Zend/zend_operators.h | 12 |
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; |