diff options
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r-- | Zend/zend_operators.c | 182 |
1 files changed, 102 insertions, 80 deletions
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index cd857ee217..f1ebb2e5df 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | @@ -568,19 +568,33 @@ try_again: case IS_ARRAY: zend_error(E_NOTICE, "Array to string conversion"); zval_ptr_dtor(op); - ZVAL_NEW_STR(op, zend_string_init("Array", sizeof("Array")-1, 0)); + ZVAL_INTERNED_STR(op, ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED)); break; case IS_OBJECT: { - zval dst; - - convert_object_to_type(op, &dst, IS_STRING, convert_to_string); - zval_ptr_dtor(op); + zval tmp; - if (Z_TYPE(dst) == IS_STRING) { - ZVAL_COPY_VALUE(op, &dst); - } else { - ZVAL_NEW_STR(op, zend_string_init("Object", sizeof("Object")-1, 0)); + if (Z_OBJ_HT_P(op)->cast_object) { + if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) { + zval_ptr_dtor(op); + ZVAL_COPY_VALUE(op, &tmp); + return; + } + } else if (Z_OBJ_HT_P(op)->get) { + zval *z = Z_OBJ_HT_P(op)->get(op, &tmp); + if (Z_TYPE_P(z) != IS_OBJECT) { + zend_string *str = zval_get_string(z); + zval_ptr_dtor(z); + zval_ptr_dtor(op); + ZVAL_STR(op, str); + return; + } + zval_ptr_dtor(z); } + if (!EG(exception)) { + zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name)); + } + zval_ptr_dtor(op); + ZVAL_EMPTY_STRING(op); break; } case IS_REFERENCE: @@ -591,6 +605,20 @@ try_again: } /* }}} */ +ZEND_API zend_bool ZEND_FASTCALL _try_convert_to_string(zval *op) +{ + zend_string *str; + + ZEND_ASSERT(Z_TYPE_P(op) != IS_STRING); + str = zval_try_get_string_func(op); + if (UNEXPECTED(!str)) { + return 0; + } + zval_ptr_dtor(op); + ZVAL_STR(op, str); + return 1; +} + static void convert_scalar_to_array(zval *op) /* {{{ */ { HashTable *ht = zend_new_array(1); @@ -610,32 +638,20 @@ try_again: if (Z_OBJCE_P(op) == zend_ce_closure) { convert_scalar_to_array(op); } else { - if (Z_OBJ_HT_P(op)->get_properties) { - HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op); - if (obj_ht) { - /* fast copy */ - obj_ht = zend_proptable_to_symtable(obj_ht, - (Z_OBJCE_P(op)->default_properties_count || - Z_OBJ_P(op)->handlers != &std_object_handlers || - GC_IS_RECURSIVE(obj_ht))); - zval_ptr_dtor(op); - ZVAL_ARR(op, obj_ht); - return; - } + HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST); + if (obj_ht) { + HashTable *new_obj_ht = zend_proptable_to_symtable(obj_ht, + (Z_OBJCE_P(op)->default_properties_count || + Z_OBJ_P(op)->handlers != &std_object_handlers || + GC_IS_RECURSIVE(obj_ht))); + zval_ptr_dtor(op); + ZVAL_ARR(op, new_obj_ht); + zend_release_properties(obj_ht); } else { - zval dst; - convert_object_to_type(op, &dst, IS_ARRAY, convert_to_array); - - if (Z_TYPE(dst) == IS_ARRAY) { - zval_ptr_dtor(op); - ZVAL_COPY_VALUE(op, &dst); - return; - } + zval_ptr_dtor(op); + /*ZVAL_EMPTY_ARRAY(op);*/ + array_init(op); } - - zval_ptr_dtor(op); - /*ZVAL_EMPTY_ARRAY(op);*/ - array_init(op); } break; case IS_NULL: @@ -850,7 +866,7 @@ try_again: } /* }}} */ -ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op) /* {{{ */ +static zend_always_inline zend_string* __zval_get_string_func(zval *op, zend_bool try) /* {{{ */ { try_again: switch (Z_TYPE_P(op)) { @@ -871,7 +887,8 @@ try_again: } case IS_ARRAY: zend_error(E_NOTICE, "Array to string conversion"); - return zend_string_init("Array", sizeof("Array")-1, 0); + return (try && UNEXPECTED(EG(exception))) ? + NULL : ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED); case IS_OBJECT: { zval tmp; if (Z_OBJ_HT_P(op)->cast_object) { @@ -881,14 +898,16 @@ try_again: } else if (Z_OBJ_HT_P(op)->get) { zval *z = Z_OBJ_HT_P(op)->get(op, &tmp); if (Z_TYPE_P(z) != IS_OBJECT) { - zend_string *str = zval_get_string(z); + zend_string *str = try ? zval_try_get_string(z) : zval_get_string(z); zval_ptr_dtor(z); return str; } zval_ptr_dtor(z); } - zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name)); - return ZSTR_EMPTY_ALLOC(); + if (!EG(exception)) { + zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name)); + } + return try ? NULL : ZSTR_EMPTY_ALLOC(); } case IS_REFERENCE: op = Z_REFVAL_P(op); @@ -901,6 +920,18 @@ try_again: } /* }}} */ +ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op) /* {{{ */ +{ + return __zval_get_string_func(op, 0); +} +/* }}} */ + +ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op) /* {{{ */ +{ + return __zval_get_string_func(op, 1); +} +/* }}} */ + static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */ { if ((result == op1) && (result == op2)) { @@ -1232,6 +1263,9 @@ ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* { } /* }}} */ +#ifdef __clang__ +__attribute__((no_sanitize("float-divide-by-zero"))) +#endif ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */ { zval op1_copy, op2_copy; @@ -1726,7 +1760,8 @@ ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op zval_ptr_dtor(result); } - ZVAL_LONG(result, op1_lval << op2_lval); + /* Perform shift on unsigned numbers to get well-defined wrap behavior. */ + ZVAL_LONG(result, (zend_long) ((zend_ulong) op1_lval << op2_lval)); return SUCCESS; } /* }}} */ @@ -1821,7 +1856,7 @@ ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) / if (UNEXPECTED(Z_STRLEN_P(op1) == 0)) { if (EXPECTED(result != op2)) { if (result == orig_op1) { - i_zval_ptr_dtor(result ZEND_FILE_LINE_CC); + i_zval_ptr_dtor(result); } ZVAL_COPY(result, op2); } @@ -1852,7 +1887,7 @@ ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) / result_str = zend_string_alloc(result_len, 0); memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len); if (result == orig_op1) { - i_zval_ptr_dtor(result ZEND_FILE_LINE_CC); + i_zval_ptr_dtor(result); } } @@ -1934,7 +1969,6 @@ ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* } /* }}} */ -#if HAVE_STRCOLL ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) /* {{{ */ { zend_string *tmp_str1, *tmp_str2; @@ -1947,7 +1981,6 @@ ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) return ret; } /* }}} */ -#endif ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ */ { @@ -2129,15 +2162,15 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) } } if (!converted) { - if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) { + if (Z_TYPE_P(op1) < IS_TRUE) { ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0); return SUCCESS; - } else if (Z_TYPE_P(op2) == IS_NULL || Z_TYPE_P(op2) == IS_FALSE) { - ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0); - return SUCCESS; } else if (Z_TYPE_P(op1) == IS_TRUE) { ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1); return SUCCESS; + } else if (Z_TYPE_P(op2) < IS_TRUE) { + ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0); + return SUCCESS; } else if (Z_TYPE_P(op2) == IS_TRUE) { ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1); return SUCCESS; @@ -2158,14 +2191,12 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) } else if (Z_TYPE_P(op2)==IS_ARRAY) { ZVAL_LONG(result, -1); return SUCCESS; - } else if (Z_TYPE_P(op1)==IS_OBJECT) { - ZVAL_LONG(result, 1); - return SUCCESS; - } else if (Z_TYPE_P(op2)==IS_OBJECT) { - ZVAL_LONG(result, -1); - return SUCCESS; } else { - ZVAL_LONG(result, 0); + ZEND_ASSERT(0); + zend_throw_error(NULL, "Unsupported operand types"); + if (result != op1) { + ZVAL_UNDEF(result); + } return FAILURE; } } @@ -2175,8 +2206,6 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ { - zval result; - /* is_identical_function() returns 1 in case of identity and 0 in case * of a difference; * whereas this comparison function is expected to return 0 on identity, @@ -2184,14 +2213,11 @@ static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ */ ZVAL_DEREF(z1); ZVAL_DEREF(z2); - if (is_identical_function(&result, z1, z2)==FAILURE) { - return 1; - } - return Z_TYPE(result) != IS_TRUE; + return fast_is_not_identical_function(z1, z2); } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ */ +ZEND_API zend_bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ */ { if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { return 0; @@ -2278,9 +2304,12 @@ static zend_bool ZEND_FASTCALL instanceof_interface_only(const zend_class_entry { uint32_t i; - for (i = 0; i < instance_ce->num_interfaces; i++) { - if (instanceof_interface_only(instance_ce->interfaces[i], ce)) { - return 1; + if (instance_ce->num_interfaces) { + ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES); + for (i = 0; i < instance_ce->num_interfaces; i++) { + if (instanceof_interface_only(instance_ce->interfaces[i], ce)) { + return 1; + } } } return 0; @@ -2303,9 +2332,12 @@ static zend_bool ZEND_FASTCALL instanceof_interface(const zend_class_entry *inst { uint32_t i; - for (i = 0; i < instance_ce->num_interfaces; i++) { - if (instanceof_interface(instance_ce->interfaces[i], ce)) { - return 1; + if (instance_ce->num_interfaces) { + ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES); + for (i = 0; i < instance_ce->num_interfaces; i++) { + if (instanceof_interface(instance_ce->interfaces[i], ce)) { + return 1; + } } } return instanceof_class(instance_ce, ce); @@ -3005,7 +3037,7 @@ ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t int digits = 0, dp_or_e = 0; double local_dval = 0.0; zend_uchar type; - zend_long tmp_lval = 0; + zend_ulong tmp_lval = 0; int neg = 0; if (!length) { @@ -3113,7 +3145,7 @@ process_double: if (neg) { tmp_lval = -tmp_lval; } - *lval = tmp_lval; + *lval = (zend_long) tmp_lval; } return IS_LONG; @@ -3254,13 +3286,3 @@ ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d) } #endif #endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ |