diff options
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r-- | Zend/zend_operators.c | 128 |
1 files changed, 98 insertions, 30 deletions
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 4619b73ef6..594f1f1057 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -27,13 +27,10 @@ #include "zend_globals.h" #include "zend_list.h" #include "zend_API.h" -#include "zend_multiply.h" #include "zend_strtod.h" #include "zend_exceptions.h" #include "zend_closures.h" -#define LONG_SIGN_MASK (1L << (8*sizeof(long)-1)) - #if ZEND_USE_TOLOWER_L #include <locale.h> static _locale_t current_locale = NULL; @@ -1199,11 +1196,18 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* must support result==op1 */ ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */ { - Z_STRLEN_P(result) = Z_STRLEN_P(op1) + 1; - Z_STRVAL_P(result) = (char *) erealloc(Z_STRVAL_P(op1), Z_STRLEN_P(result)+1); - Z_STRVAL_P(result)[Z_STRLEN_P(result) - 1] = (char) Z_LVAL_P(op2); - Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0; - Z_TYPE_P(result) = IS_STRING; + int length = Z_STRLEN_P(op1) + 1; + char *buf; + + if (IS_INTERNED(Z_STRVAL_P(op1))) { + buf = (char *) emalloc(length + 1); + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); + } else { + buf = (char *) erealloc(Z_STRVAL_P(op1), length + 1); + } + buf[length - 1] = (char) Z_LVAL_P(op2); + buf[length] = 0; + ZVAL_STRINGL(result, buf, length, 0); return SUCCESS; } /* }}} */ @@ -1212,12 +1216,17 @@ ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */ { int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); + char *buf; - Z_STRVAL_P(result) = (char *) erealloc(Z_STRVAL_P(op1), length+1); - memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); - Z_STRVAL_P(result)[length] = 0; - Z_STRLEN_P(result) = length; - Z_TYPE_P(result) = IS_STRING; + if (IS_INTERNED(Z_STRVAL_P(op1))) { + buf = (char *) emalloc(length+1); + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); + } else { + buf = (char *) erealloc(Z_STRVAL_P(op1), length+1); + } + memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); + buf[length] = 0; + ZVAL_STRINGL(result, buf, length, 0); return SUCCESS; } /* }}} */ @@ -1246,7 +1255,7 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ if (use_copy2) { op2 = &op2_copy; } - if (result==op1) { /* special case, perform operations on result */ + if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) { /* special case, perform operations on result */ uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) { @@ -1261,12 +1270,13 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ Z_STRVAL_P(result)[res_len]=0; Z_STRLEN_P(result) = res_len; } else { - Z_STRLEN_P(result) = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); - Z_STRVAL_P(result) = (char *) emalloc(Z_STRLEN_P(result) + 1); - memcpy(Z_STRVAL_P(result), Z_STRVAL_P(op1), Z_STRLEN_P(op1)); - memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); - Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0; - Z_TYPE_P(result) = IS_STRING; + int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); + char *buf = (char *) emalloc(length + 1); + + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); + memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); + buf[length] = 0; + ZVAL_STRINGL(result, buf, length, 0); } if (use_copy1) { zval_dtor(op1); @@ -1278,7 +1288,7 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ } /* }}} */ -ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */ { zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; @@ -1297,7 +1307,11 @@ ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_D op2 = &op2_copy; } - ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2)); + if (case_insensitive) { + ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2)); + } else { + ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2)); + } if (use_copy1) { zval_dtor(op1); @@ -1309,6 +1323,18 @@ ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_D } /* }}} */ +ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC); +} +/* }}} */ + +ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC); +} +/* }}} */ + #if HAVE_STRCOLL ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { @@ -1397,8 +1423,12 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE): - Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2); - ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result))); + if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) { + ZVAL_LONG(result, 0); + } else { + Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2); + ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result))); + } return SUCCESS; case TYPE_PAIR(IS_ARRAY, IS_ARRAY): @@ -1694,6 +1724,12 @@ static void increment_string(zval *str) /* {{{ */ return; } + if (IS_INTERNED(s)) { + s = (char*) emalloc(Z_STRLEN_P(str) + 1); + memcpy(s, Z_STRVAL_P(str), Z_STRLEN_P(str) + 1); + Z_STRVAL_P(str) = s; + } + while (pos >= 0) { ch = s[pos]; if (ch >= 'a' && ch <= 'z') { @@ -1779,7 +1815,7 @@ ZEND_API int increment_function(zval *op1) /* {{{ */ switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) { case IS_LONG: - efree(Z_STRVAL_P(op1)); + str_efree(Z_STRVAL_P(op1)); if (lval == LONG_MAX) { /* switch to double */ double d = (double)lval; @@ -1789,7 +1825,7 @@ ZEND_API int increment_function(zval *op1) /* {{{ */ } break; case IS_DOUBLE: - efree(Z_STRVAL_P(op1)); + str_efree(Z_STRVAL_P(op1)); ZVAL_DOUBLE(op1, dval+1); break; default: @@ -1905,6 +1941,9 @@ ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint { int retval; + if (s1 == s2) { + return 0; + } retval = memcmp(s1, s2, MIN(len1, len2)); if (!retval) { return (len1 - len2); @@ -1918,6 +1957,9 @@ ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint { int retval; + if (s1 == s2) { + return 0; + } retval = memcmp(s1, s2, MIN(length, MIN(len1, len2))); if (!retval) { return (MIN(length, len1) - MIN(length, len2)); @@ -1932,8 +1974,11 @@ ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, u int len; int c1, c2; - len = MIN(len1, len2); + if (s1 == s2) { + return 0; + } + len = MIN(len1, len2); while (len--) { c1 = zend_tolower((int)*(unsigned char *)s1++); c2 = zend_tolower((int)*(unsigned char *)s2++); @@ -1951,8 +1996,10 @@ ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, int len; int c1, c2; + if (s1 == s2) { + return 0; + } len = MIN(length, MIN(len1, len2)); - while (len--) { c1 = zend_tolower((int)*(unsigned char *)s1++); c2 = zend_tolower((int)*(unsigned char *)s2++); @@ -1992,15 +2039,36 @@ ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ * ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */ { int ret1, ret2; + int oflow1, oflow2; long lval1, lval2; double dval1, dval2; - if ((ret1=is_numeric_string(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0)) && - (ret2=is_numeric_string(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0))) { + if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) && + (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) { +#if 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) */ + ZVAL_LONG(result, -1 * oflow2); + return; + } dval1 = (double) lval1; } else if (ret2!=IS_DOUBLE) { + if (oflow1) { + ZVAL_LONG(result, oflow1); + return; + } dval2 = (double) lval2; } else if (dval1 == dval2 && !zend_finite(dval1)) { /* Both values overflowed and have the same sign, |