summaryrefslogtreecommitdiff
path: root/Zend/zend_operators.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r--Zend/zend_operators.c128
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,