Skip to content

Commit bef4b2e

Browse files
committed
Report object cast failures internally
Make cast_object return FAILURE for casts to int/float, rather than throwing a notice and returning SUCCESS. Instead move the emission of the notice to the code invoking cast_object. This will allow us to customize the behavior per call-site. This change is written to be NFC, and the code in zend_std_compare_objects() should illustrate the current behavior doesn't make a lot of sense.
1 parent 78d3af4 commit bef4b2e

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

Zend/zend_object_handlers.c

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,8 +1573,21 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
15731573
if (Z_TYPE_P(o1) == IS_OBJECT) {
15741574
ZEND_ASSERT(Z_TYPE_P(o2) != IS_OBJECT);
15751575
if (Z_OBJ_HT_P(o1)->cast_object) {
1576-
if (Z_OBJ_HT_P(o1)->cast_object(Z_OBJ_P(o1), &casted, ((Z_TYPE_P(o2) == IS_FALSE || Z_TYPE_P(o2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(o2))) == FAILURE) {
1577-
return 1;
1576+
zend_uchar target_type = (Z_TYPE_P(o2) == IS_FALSE || Z_TYPE_P(o2) == IS_TRUE)
1577+
? _IS_BOOL : Z_TYPE_P(o2);
1578+
if (Z_OBJ_HT_P(o1)->cast_object(Z_OBJ_P(o1), &casted, target_type) == FAILURE) {
1579+
// TODO: Less crazy.
1580+
if (target_type == IS_LONG || target_type == IS_DOUBLE) {
1581+
zend_error(E_NOTICE, "Object of class %s could not be converted to %s",
1582+
ZSTR_VAL(Z_OBJCE_P(o1)->name), zend_get_type_by_const(target_type));
1583+
if (target_type == IS_LONG) {
1584+
ZVAL_LONG(&casted, 1);
1585+
} else {
1586+
ZVAL_DOUBLE(&casted, 1.0);
1587+
}
1588+
} else {
1589+
return 1;
1590+
}
15781591
}
15791592
int ret = zend_compare(&casted, o2);
15801593
zval_ptr_dtor(&casted);
@@ -1583,8 +1596,21 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
15831596
} else {
15841597
ZEND_ASSERT(Z_TYPE_P(o2) == IS_OBJECT);
15851598
if (Z_OBJ_HT_P(o2)->cast_object) {
1586-
if (Z_OBJ_HT_P(o2)->cast_object(Z_OBJ_P(o2), &casted, ((Z_TYPE_P(o1) == IS_FALSE || Z_TYPE_P(o1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(o1))) == FAILURE) {
1587-
return -1;
1599+
zend_uchar target_type = (Z_TYPE_P(o1) == IS_FALSE || Z_TYPE_P(o1) == IS_TRUE)
1600+
? _IS_BOOL : Z_TYPE_P(o1);
1601+
if (Z_OBJ_HT_P(o2)->cast_object(Z_OBJ_P(o2), &casted, target_type) == FAILURE) {
1602+
// TODO: Less crazy.
1603+
if (target_type == IS_LONG || target_type == IS_DOUBLE) {
1604+
zend_error(E_NOTICE, "Object of class %s could not be converted to %s",
1605+
ZSTR_VAL(Z_OBJCE_P(o2)->name), zend_get_type_by_const(target_type));
1606+
if (target_type == IS_LONG) {
1607+
ZVAL_LONG(&casted, 1);
1608+
} else {
1609+
ZVAL_DOUBLE(&casted, 1.0);
1610+
}
1611+
} else {
1612+
return -1;
1613+
}
15881614
}
15891615
int ret = zend_compare(o1, &casted);
15901616
zval_ptr_dtor(&casted);
@@ -1773,13 +1799,11 @@ ZEND_API zend_string *zend_std_get_class_name(const zend_object *zobj) /* {{{ */
17731799

17741800
ZEND_API int zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj, int type) /* {{{ */
17751801
{
1776-
zval retval;
1777-
zend_class_entry *ce;
1778-
17791802
switch (type) {
1780-
case IS_STRING:
1781-
ce = readobj->ce;
1803+
case IS_STRING: {
1804+
zend_class_entry *ce = readobj->ce;
17821805
if (ce->__tostring) {
1806+
zval retval;
17831807
zend_call_method_with_0_params(readobj, ce, &ce->__tostring, "__tostring", &retval);
17841808
if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
17851809
ZVAL_COPY_VALUE(writeobj, &retval);
@@ -1791,29 +1815,13 @@ ZEND_API int zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj,
17911815
}
17921816
}
17931817
return FAILURE;
1818+
}
17941819
case _IS_BOOL:
17951820
ZVAL_TRUE(writeobj);
17961821
return SUCCESS;
1797-
case IS_LONG:
1798-
ce = readobj->ce;
1799-
zend_error(E_NOTICE, "Object of class %s could not be converted to int", ZSTR_VAL(ce->name));
1800-
ZVAL_LONG(writeobj, 1);
1801-
return SUCCESS;
1802-
case IS_DOUBLE:
1803-
ce = readobj->ce;
1804-
zend_error(E_NOTICE, "Object of class %s could not be converted to float", ZSTR_VAL(ce->name));
1805-
ZVAL_DOUBLE(writeobj, 1);
1806-
return SUCCESS;
1807-
case _IS_NUMBER:
1808-
ce = readobj->ce;
1809-
zend_error(E_NOTICE, "Object of class %s could not be converted to number", ZSTR_VAL(ce->name));
1810-
ZVAL_LONG(writeobj, 1);
1811-
return SUCCESS;
18121822
default:
1813-
ZVAL_NULL(writeobj);
1814-
break;
1823+
return FAILURE;
18151824
}
1816-
return FAILURE;
18171825
}
18181826
/* }}} */
18191827

Zend/zend_operators.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* {
139139
ZVAL_UNDEF(dst); \
140140
if (Z_OBJ_HT_P(op)->cast_object) { \
141141
if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), dst, ctype) == FAILURE) { \
142-
zend_error(E_RECOVERABLE_ERROR, \
142+
zend_error(E_NOTICE, \
143143
"Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
144144
zend_get_type_by_const(ctype)); \
145145
} \

0 commit comments

Comments
 (0)