diff options
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r-- | Zend/zend_operators.c | 251 |
1 files changed, 167 insertions, 84 deletions
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 683ab3c5cf..3434694f4c 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -192,7 +192,7 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) /* {{{ */ if ((Z_TYPE_P(op)=is_numeric_string(strval, Z_STRLEN_P(op), &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) { ZVAL_LONG(op, 0); } - STR_FREE(strval); + str_efree(strval); break; } case IS_BOOL: @@ -391,7 +391,7 @@ ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */ char *strval = Z_STRVAL_P(op); Z_LVAL_P(op) = strtol(strval, NULL, base); - STR_FREE(strval); + str_efree(strval); } break; case IS_ARRAY: @@ -451,7 +451,7 @@ ZEND_API void convert_to_double(zval *op) /* {{{ */ char *strval = Z_STRVAL_P(op); Z_DVAL_P(op) = zend_strtod(strval, NULL); - STR_FREE(strval); + str_efree(strval); } break; case IS_ARRAY: @@ -540,7 +540,7 @@ ZEND_API void convert_to_boolean(zval *op) /* {{{ */ } else { Z_LVAL_P(op) = 1; } - STR_FREE(strval); + str_efree(strval); } break; case IS_ARRAY: @@ -857,6 +857,8 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD); + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -904,6 +906,8 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB); + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -945,6 +949,8 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL); + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -1010,6 +1016,8 @@ ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV); + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -1027,9 +1035,15 @@ ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * zval op1_copy, op2_copy; long op1_lval; - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } if (Z_LVAL_P(op2) == 0) { zend_error(E_WARNING, "Division by zero"); @@ -1053,9 +1067,16 @@ ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; long op1_lval; - zendi_convert_to_boolean(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_boolean(op2, op2_copy, result); + if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR); + + zendi_convert_to_boolean(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_boolean(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } + ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2)); return SUCCESS; } @@ -1065,7 +1086,12 @@ ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { zval op1_copy; - zendi_convert_to_boolean(op1, op1_copy, result); + if (Z_TYPE_P(op1) != IS_BOOL) { + ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT); + + zendi_convert_to_boolean(op1, op1_copy, result); + } + ZVAL_BOOL(result, !Z_LVAL_P(op1)); return SUCCESS; } @@ -1073,29 +1099,32 @@ ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { - zval op1_copy = *op1; - - op1 = &op1_copy; - if (Z_TYPE_P(op1) == IS_LONG) { - ZVAL_LONG(result, ~Z_LVAL_P(op1)); - return SUCCESS; - } else if (Z_TYPE_P(op1) == IS_DOUBLE) { - ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1))); - return SUCCESS; - } else if (Z_TYPE_P(op1) == IS_STRING) { - int i; - - Z_TYPE_P(result) = IS_STRING; - Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1)); - Z_STRLEN_P(result) = Z_STRLEN_P(op1); - for (i = 0; i < Z_STRLEN_P(op1); i++) { - Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i]; + switch (Z_TYPE_P(op1)) { + case IS_LONG: + ZVAL_LONG(result, ~Z_LVAL_P(op1)); + return SUCCESS; + case IS_DOUBLE: + ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1))); + return SUCCESS; + case IS_STRING: { + int i; + zval op1_copy = *op1; + + Z_TYPE_P(result) = IS_STRING; + Z_STRVAL_P(result) = estrndup(Z_STRVAL(op1_copy), Z_STRLEN(op1_copy)); + Z_STRLEN_P(result) = Z_STRLEN(op1_copy); + for (i = 0; i < Z_STRLEN(op1_copy); i++) { + Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i]; + } + return SUCCESS; } - return SUCCESS; + default: + ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT); + + zend_error(E_ERROR, "Unsupported operand types"); + return FAILURE; } - zend_error(E_ERROR, "Unsupported operand types"); - return FAILURE; /* unknown datatype */ } /* }}} */ @@ -1124,15 +1153,22 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / result_str[i] |= Z_STRVAL_P(shorter)[i]; } if (result==op1) { - STR_FREE(Z_STRVAL_P(result)); + str_efree(Z_STRVAL_P(result)); } Z_STRVAL_P(result) = result_str; Z_STRLEN_P(result) = result_len; return SUCCESS; } - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2)); return SUCCESS; @@ -1164,17 +1200,22 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result_str[i] &= Z_STRVAL_P(longer)[i]; } if (result==op1) { - STR_FREE(Z_STRVAL_P(result)); + str_efree(Z_STRVAL_P(result)); } Z_STRVAL_P(result) = result_str; Z_STRLEN_P(result) = result_len; return SUCCESS; } + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND); - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2)); return SUCCESS; @@ -1206,16 +1247,22 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result_str[i] ^= Z_STRVAL_P(longer)[i]; } if (result==op1) { - STR_FREE(Z_STRVAL_P(result)); + str_efree(Z_STRVAL_P(result)); } Z_STRVAL_P(result) = result_str; Z_STRLEN_P(result) = result_len; return SUCCESS; } - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2)); return SUCCESS; @@ -1227,9 +1274,16 @@ ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / zval op1_copy, op2_copy; long op1_lval; - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } + ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2)); return SUCCESS; } @@ -1240,9 +1294,16 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; long op1_lval; - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } + ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2)); return SUCCESS; } @@ -1252,14 +1313,8 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */ { int length = Z_STRLEN_P(op1) + 1; - char *buf; + char *buf = str_erealloc(Z_STRVAL_P(op1), length + 1); - 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); @@ -1271,14 +1326,8 @@ 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; + char *buf = str_erealloc(Z_STRVAL_P(op1), length + 1); - 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); @@ -1291,11 +1340,15 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; - if (Z_TYPE_P(op1) != IS_STRING) { - zend_make_printable_zval(op1, &op1_copy, &use_copy1); - } - if (Z_TYPE_P(op2) != IS_STRING) { - zend_make_printable_zval(op2, &op2_copy, &use_copy2); + if (Z_TYPE_P(op1) != IS_STRING || Z_TYPE_P(op2) != IS_STRING) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT); + + if (Z_TYPE_P(op1) != IS_STRING) { + zend_make_printable_zval(op1, &op1_copy, &use_copy1); + } + if (Z_TYPE_P(op2) != IS_STRING) { + zend_make_printable_zval(op2, &op2_copy, &use_copy2); + } } if (use_copy1) { @@ -1526,20 +1579,24 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { ZVAL_LONG(result, -1); return SUCCESS; - case TYPE_PAIR(IS_OBJECT, IS_OBJECT): - /* If both are objects sharing the same comparision handler then use is */ - if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) { + default: + if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) { + return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC); + } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) { + return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC); + } + + if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) { if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) { /* object handles are identical, apparently this is the same object */ ZVAL_LONG(result, 0); return SUCCESS; } - ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC)); - return SUCCESS; + if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) { + ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC)); + return SUCCESS; + } } - /* break missing intentionally */ - - default: if (Z_TYPE_P(op1) == IS_OBJECT) { if (Z_OBJ_HT_P(op1)->get) { op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC); @@ -1773,16 +1830,14 @@ static void increment_string(zval *str) /* {{{ */ int ch; if (Z_STRLEN_P(str) == 0) { - STR_FREE(Z_STRVAL_P(str)); + str_efree(Z_STRVAL_P(str)); Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1); Z_STRLEN_P(str) = 1; 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; + Z_STRVAL_P(str) = s = estrndup(s, Z_STRLEN_P(str)); } while (pos >= 0) { @@ -1840,7 +1895,7 @@ static void increment_string(zval *str) /* {{{ */ t[0] = 'a'; break; } - STR_FREE(Z_STRVAL_P(str)); + str_efree(Z_STRVAL_P(str)); Z_STRVAL_P(str) = t; } } @@ -1890,6 +1945,20 @@ ZEND_API int increment_function(zval *op1) /* {{{ */ } } break; + case IS_OBJECT: + if (Z_OBJ_HANDLER_P(op1, do_operation)) { + zval *op2; + int res; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(op2); + ZVAL_LONG(op2, 1); + res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC); + zval_ptr_dtor(&op2); + + return res; + } + return FAILURE; default: return FAILURE; } @@ -1916,13 +1985,13 @@ ZEND_API int decrement_function(zval *op1) /* {{{ */ break; case IS_STRING: /* Like perl we only support string increment */ if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */ - STR_FREE(Z_STRVAL_P(op1)); + str_efree(Z_STRVAL_P(op1)); ZVAL_LONG(op1, -1); break; } switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) { case IS_LONG: - STR_FREE(Z_STRVAL_P(op1)); + str_efree(Z_STRVAL_P(op1)); if (lval == LONG_MIN) { double d = (double)lval; ZVAL_DOUBLE(op1, d-1); @@ -1931,11 +2000,25 @@ ZEND_API int decrement_function(zval *op1) /* {{{ */ } break; case IS_DOUBLE: - STR_FREE(Z_STRVAL_P(op1)); + str_efree(Z_STRVAL_P(op1)); ZVAL_DOUBLE(op1, dval - 1); break; } break; + case IS_OBJECT: + if (Z_OBJ_HANDLER_P(op1, do_operation)) { + zval *op2; + int res; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(op2); + ZVAL_LONG(op2, 1); + res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC); + zval_ptr_dtor(&op2); + + return res; + } + return FAILURE; default: return FAILURE; } |