]> granicus.if.org Git - php/commitdiff
Added zendi_smart_streq() for smart string equality check
authorDmitry Stogov <dmitry@zend.com>
Tue, 16 Jan 2018 14:24:00 +0000 (17:24 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 16 Jan 2018 14:24:00 +0000 (17:24 +0300)
Zend/zend_operators.c
Zend/zend_operators.h

index a8af4bf3f722075871596f93a7d2b80b4d60d870..dc6f2d6352dd6cc542faa0011018f35522c47257 100644 (file)
@@ -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;
index 87c8c5a33bc6e89f3fbc8def8fc9e09fb80acff6..a815427286aaf3c926ed0a08e05a4045ddaf0189 100644 (file)
@@ -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);
        }
 }