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.c182
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
- */