l. Some VM instructions switched to IS_TMP_VAR result instead of IS_VAR
m. All internal functions must have arginfo
n. zend_hash_sort compare function signature change
+ o. cast_object() object handler is now required
2. Build system changes
a. Abstract
Previously compare_func_t was used, which accepted void pointers.
+ o. The cast_object() handler is now required, i.e. must be non-null. You can
+ indicate that casting is not supported by always returning FAILURE.
+
========================
2. Build system changes
========================
*dest = Z_STR_P(arg);
} else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
zend_object *zobj = Z_OBJ_P(arg);
-
- if (Z_OBJ_HANDLER_P(arg, cast_object)) {
- zval obj;
- if (zobj->handlers->cast_object(zobj, &obj, IS_STRING) == SUCCESS) {
- OBJ_RELEASE(zobj);
- ZVAL_COPY_VALUE(arg, &obj);
- *dest = Z_STR_P(arg);
- return 1;
- }
+ zval obj;
+ if (zobj->handlers->cast_object(zobj, &obj, IS_STRING) == SUCCESS) {
+ OBJ_RELEASE(zobj);
+ ZVAL_COPY_VALUE(arg, &obj);
+ *dest = Z_STR_P(arg);
+ return 1;
}
return 0;
} else {
}
break;
case IS_OBJECT:
- if (Z_OBJ_HT_P(val)->cast_object) {
- if (Z_OBJ_HT_P(val)->cast_object(Z_OBJ_P(val), &val_free, IS_STRING) == SUCCESS) {
- val = &val_free;
- break;
- }
+ if (Z_OBJ_HT_P(val)->cast_object(Z_OBJ_P(val), &val_free, IS_STRING) == SUCCESS) {
+ val = &val_free;
+ break;
}
/* no break */
default:
zval casted;
if (Z_TYPE_P(o1) == IS_OBJECT) {
ZEND_ASSERT(Z_TYPE_P(o2) != IS_OBJECT);
- if (Z_OBJ_HT_P(o1)->cast_object) {
- zend_uchar target_type = (Z_TYPE_P(o2) == IS_FALSE || Z_TYPE_P(o2) == IS_TRUE)
- ? _IS_BOOL : Z_TYPE_P(o2);
- if (Z_OBJ_HT_P(o1)->cast_object(Z_OBJ_P(o1), &casted, target_type) == FAILURE) {
- // TODO: Less crazy.
- if (target_type == IS_LONG || target_type == IS_DOUBLE) {
- zend_error(E_NOTICE, "Object of class %s could not be converted to %s",
- ZSTR_VAL(Z_OBJCE_P(o1)->name), zend_get_type_by_const(target_type));
- if (target_type == IS_LONG) {
- ZVAL_LONG(&casted, 1);
- } else {
- ZVAL_DOUBLE(&casted, 1.0);
- }
+ zend_uchar target_type = (Z_TYPE_P(o2) == IS_FALSE || Z_TYPE_P(o2) == IS_TRUE)
+ ? _IS_BOOL : Z_TYPE_P(o2);
+ if (Z_OBJ_HT_P(o1)->cast_object(Z_OBJ_P(o1), &casted, target_type) == FAILURE) {
+ // TODO: Less crazy.
+ if (target_type == IS_LONG || target_type == IS_DOUBLE) {
+ zend_error(E_NOTICE, "Object of class %s could not be converted to %s",
+ ZSTR_VAL(Z_OBJCE_P(o1)->name), zend_get_type_by_const(target_type));
+ if (target_type == IS_LONG) {
+ ZVAL_LONG(&casted, 1);
} else {
- return 1;
+ ZVAL_DOUBLE(&casted, 1.0);
}
+ } else {
+ return 1;
}
- int ret = zend_compare(&casted, o2);
- zval_ptr_dtor(&casted);
- return ret;
}
+ int ret = zend_compare(&casted, o2);
+ zval_ptr_dtor(&casted);
+ return ret;
} else {
ZEND_ASSERT(Z_TYPE_P(o2) == IS_OBJECT);
- if (Z_OBJ_HT_P(o2)->cast_object) {
- zend_uchar target_type = (Z_TYPE_P(o1) == IS_FALSE || Z_TYPE_P(o1) == IS_TRUE)
- ? _IS_BOOL : Z_TYPE_P(o1);
- if (Z_OBJ_HT_P(o2)->cast_object(Z_OBJ_P(o2), &casted, target_type) == FAILURE) {
- // TODO: Less crazy.
- if (target_type == IS_LONG || target_type == IS_DOUBLE) {
- zend_error(E_NOTICE, "Object of class %s could not be converted to %s",
- ZSTR_VAL(Z_OBJCE_P(o2)->name), zend_get_type_by_const(target_type));
- if (target_type == IS_LONG) {
- ZVAL_LONG(&casted, 1);
- } else {
- ZVAL_DOUBLE(&casted, 1.0);
- }
+ zend_uchar target_type = (Z_TYPE_P(o1) == IS_FALSE || Z_TYPE_P(o1) == IS_TRUE)
+ ? _IS_BOOL : Z_TYPE_P(o1);
+ if (Z_OBJ_HT_P(o2)->cast_object(Z_OBJ_P(o2), &casted, target_type) == FAILURE) {
+ // TODO: Less crazy.
+ if (target_type == IS_LONG || target_type == IS_DOUBLE) {
+ zend_error(E_NOTICE, "Object of class %s could not be converted to %s",
+ ZSTR_VAL(Z_OBJCE_P(o2)->name), zend_get_type_by_const(target_type));
+ if (target_type == IS_LONG) {
+ ZVAL_LONG(&casted, 1);
} else {
- return -1;
+ ZVAL_DOUBLE(&casted, 1.0);
}
+ } else {
+ return -1;
}
- int ret = zend_compare(o1, &casted);
- zval_ptr_dtor(&casted);
- return ret;
}
+ int ret = zend_compare(o1, &casted);
+ zval_ptr_dtor(&casted);
+ return ret;
}
return ZEND_UNCOMPARABLE;
}
zend_object_get_method_t get_method; /* required */
zend_object_get_constructor_t get_constructor; /* required */
zend_object_get_class_name_t get_class_name; /* required */
- zend_object_cast_t cast_object; /* optional */
+ zend_object_cast_t cast_object; /* required */
zend_object_count_elements_t count_elements; /* optional */
zend_object_get_debug_info_t get_debug_info; /* optional */
zend_object_get_closure_t get_closure; /* optional */
/* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
#define convert_object_to_type(op, dst, ctype, conv_func) \
ZVAL_UNDEF(dst); \
- if (Z_OBJ_HT_P(op)->cast_object) { \
- if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), dst, ctype) == FAILURE) { \
- zend_error(E_NOTICE, \
- "Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
- zend_get_type_by_const(ctype)); \
- } \
- }
+ if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), dst, ctype) == FAILURE) { \
+ zend_error(E_NOTICE, \
+ "Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
+ zend_get_type_by_const(ctype)); \
+ } \
/* }}} */
break;
case IS_OBJECT: {
zval tmp;
-
- if (Z_OBJ_HT_P(op)->cast_object) {
- if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
- zval_ptr_dtor(op);
- ZVAL_COPY_VALUE(op, &tmp);
- return;
- }
+ if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
+ zval_ptr_dtor(op);
+ ZVAL_COPY_VALUE(op, &tmp);
+ return;
}
if (!EG(exception)) {
zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
NULL : ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
case IS_OBJECT: {
zval tmp;
- if (Z_OBJ_HT_P(op)->cast_object) {
- if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
- return Z_STR(tmp);
- }
+ if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
+ return Z_STR(tmp);
}
if (!EG(exception)) {
zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
ZEND_API int ZEND_FASTCALL zend_object_is_true(zval *op) /* {{{ */
{
zend_object *zobj = Z_OBJ_P(op);
-
- if (zobj->handlers->cast_object) {
- zval tmp;
- if (zobj->handlers->cast_object(zobj, &tmp, _IS_BOOL) == SUCCESS) {
- return Z_TYPE(tmp) == IS_TRUE;
- }
- zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to bool", ZSTR_VAL(zobj->ce->name));
+ zval tmp;
+ if (zobj->handlers->cast_object(zobj, &tmp, _IS_BOOL) == SUCCESS) {
+ return Z_TYPE(tmp) == IS_TRUE;
}
+ zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to bool", ZSTR_VAL(zobj->ce->name));
return 1;
}
/* }}} */
}
/* }}} */
+static int zend_fake_cast_object(zend_object *obj, zval *result, int type)
+{
+ return FAILURE;
+}
+
static ZEND_COLD zend_never_inline void zend_ffi_use_after_free(void) /* {{{ */
{
zend_throw_error(zend_ffi_exception_ce, "Use after free()");
zend_ffi_handlers.unset_dimension = zend_fake_unset_dimension;
zend_ffi_handlers.get_method = zend_ffi_get_func;
zend_ffi_handlers.compare = NULL;
- zend_ffi_handlers.cast_object = NULL;
+ zend_ffi_handlers.cast_object = zend_fake_cast_object;
zend_ffi_handlers.get_debug_info = NULL;
zend_ffi_handlers.get_closure = NULL;
zend_ffi_handlers.get_properties = zend_fake_get_properties;
zend_ffi_cdata_free_handlers.get_method = zend_fake_get_method;
zend_ffi_cdata_free_handlers.get_class_name = zend_ffi_cdata_get_class_name;
zend_ffi_cdata_free_handlers.compare = zend_ffi_cdata_compare_objects;
- zend_ffi_cdata_free_handlers.cast_object = NULL;
+ zend_ffi_cdata_free_handlers.cast_object = zend_fake_cast_object;
zend_ffi_cdata_free_handlers.count_elements = NULL;
zend_ffi_cdata_free_handlers.get_debug_info = zend_ffi_free_get_debug_info;
zend_ffi_cdata_free_handlers.get_closure = NULL;
zend_ffi_ctype_handlers.get_method = zend_fake_get_method;
zend_ffi_ctype_handlers.get_class_name = zend_ffi_ctype_get_class_name;
zend_ffi_ctype_handlers.compare = zend_ffi_ctype_compare_objects;
- zend_ffi_ctype_handlers.cast_object = NULL;
+ zend_ffi_ctype_handlers.cast_object = zend_fake_cast_object;
zend_ffi_ctype_handlers.count_elements = NULL;
zend_ffi_ctype_handlers.get_debug_info = zend_ffi_ctype_get_debug_info;
zend_ffi_ctype_handlers.get_closure = NULL;
}
/* Try object's handlers. */
- if( Z_OBJ_HT_P(obj)->cast_object )
- {
- zstr = rv;
+ zstr = rv;
- if( Z_OBJ_HT_P(obj)->cast_object( Z_OBJ_P(obj), zstr, IS_STRING ) == FAILURE )
- {
- /* cast_object failed => bail out. */
- zval_ptr_dtor( zstr );
- COLLATOR_CONVERT_RETURN_FAILED( obj );
- }
+ if( Z_OBJ_HT_P(obj)->cast_object( Z_OBJ_P(obj), zstr, IS_STRING ) == FAILURE )
+ {
+ /* cast_object failed => bail out. */
+ zval_ptr_dtor( zstr );
+ COLLATOR_CONVERT_RETURN_FAILED( obj );
}
/* Object wasn't successfully converted => bail out. */