From: Dmitry Stogov Date: Tue, 16 Jan 2018 14:24:00 +0000 (+0300) Subject: Added zendi_smart_streq() for smart string equality check X-Git-Tag: php-7.3.0alpha1~613 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=19676fdf55ac2fa473ab8095fee06b5bdd299aee;p=php Added zendi_smart_streq() for smart string equality check --- diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index a8af4bf3f7..dc6f2d6352 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2791,6 +2791,54 @@ ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval } /* }}} */ +ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /* {{{ */ +{ + int ret1, ret2; + int oflow1, oflow2; + zend_long lval1 = 0, lval2 = 0; + double dval1 = 0.0, dval2 = 0.0; + + if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, 0, &oflow1)) && + (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, 0, &oflow2))) { +#if ZEND_ULONG_MAX == 0xFFFFFFFF + if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. && + ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/) + || (oflow1 == -1 && dval1 < -9007199254740991.))) { +#else + if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) { +#endif + /* both values are integers overflown to the same side, and the + * double comparison may have resulted in crucial accuracy lost */ + goto string_cmp; + } + if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) { + if (ret1 != IS_DOUBLE) { + if (oflow2) { + /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */ + return 0; + } + dval1 = (double) lval1; + } else if (ret2 != IS_DOUBLE) { + if (oflow1) { + return 0; + } + dval2 = (double) lval2; + } else if (dval1 == dval2 && !zend_finite(dval1)) { + /* Both values overflowed and have the same sign, + * so a numeric comparison would be inaccurate */ + goto string_cmp; + } + return dval1 == dval2; + } else { /* they both have to be long's */ + return lval1 == lval2; + } + } else { +string_cmp: + return zend_string_equal_content(s1, s2); + } +} +/* }}} */ + ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */ { int ret1, ret2; diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 87c8c5a33b..a815427286 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -386,6 +386,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2); ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length); +ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2); ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2); ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2); ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2); @@ -728,7 +729,7 @@ static zend_always_inline int zend_fast_equal_strings(zend_string *s1, zend_stri } else if (ZSTR_VAL(s1)[0] > '9' || ZSTR_VAL(s2)[0] > '9') { return zend_string_equal_content(s1, s2); } else { - return zendi_smart_strcmp(s1, s2) == 0; + return zendi_smart_streq(s1, s2); } }