From 348feb7a4e0f83339be928d205da49ae1d834f89 Mon Sep 17 00:00:00 2001 From: Jordan LeDoux Date: Wed, 19 Jan 2022 16:22:48 -0800 Subject: [PATCH 1/5] Added fallthrough for == operator with objects for extensions --- Zend/zend_operators.c | 54 ++++++++++++++++++++++++++++++++++++++++++- Zend/zend_operators.h | 1 + Zend/zend_vm_def.h | 12 ++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index de3664f5c653f..f90181b21ee8a 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -118,7 +118,7 @@ ZEND_API const unsigned char zend_toupper_map[256] = { 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, -0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff +0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff }; @@ -2132,6 +2132,58 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */ } /* }}} */ +ZEND_API int ZEND_FASTCALL zend_equals_object(zval *op1, zval *op2, zend_uchar equals) /* {{{ */ +{ + zval ret; + int retVal; + int result; + zend_function *op_handler; + if (Z_TYPE_P(op1) == IS_OBJECT && + Z_TYPE_P(op2) == IS_OBJECT && + Z_OBJ_P(op1) == Z_OBJ_P(op2)) { + return 0; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + if (Z_OBJ_HANDLER_P(op1, do_operation)) { + result = Z_OBJ_HANDLER_P(op1, do_operation)(equals, &ret, op1, op2); + if (result == FAILURE) { + goto op2_equals_handler; + } else { + retVal = (Z_TYPE_INFO(ret) == IS_TRUE ? 0 : ZEND_UNCOMPARABLE); + } + return retVal; + } else { + if (Z_TYPE_P(op2) == IS_OBJECT) { + goto op2_equals_handler; + } else { + goto default_equals_handler; + } + } + } else if (Z_TYPE_P(op2) == IS_OBJECT) { +op2_equals_handler: + if (Z_OBJ_HANDLER_P(op2, do_operation)) { + result = Z_OBJ_HANDLER_P(op2, do_operation)(equals, &ret, op1, op2); + if (result == FAILURE) { + goto default_equals_handler; + } else { + retVal = (Z_TYPE_INFO(ret) == IS_TRUE ? 0 : ZEND_UNCOMPARABLE); + } + return retVal; + } else { + if (Z_TYPE_P(op2) == IS_OBJECT) { + goto op2_equals_handler; + } else { + goto default_equals_handler; + } + } + } else { +default_equals_handler: + return zend_compare(op1, op2); + } +} +/* }}} */ + + + ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */ { int converted = 0; diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index eb88eedb79da1..b51c0905a7392 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -423,6 +423,7 @@ static zend_always_inline bool i_zend_is_true(zval *op) // TODO: Use a different value to allow an actual distinction here. #define ZEND_UNCOMPARABLE 1 +ZEND_API int ZEND_FASTCALL zend_equals_object(zval *op1, zval *op2, zend_uchar equals); ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2); ZEND_API zend_result ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index dffd3924be82b..9cc8b365683cf 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -501,7 +501,11 @@ ZEND_VM_HELPER(zend_is_equal_helper, ANY, ANY, zval *op_1, zval *op_2) if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { op_2 = ZVAL_UNDEFINED_OP2(); } - ret = zend_compare(op_1, op_2); + if (Z_TYPE_P(op_1) == IS_OBJECT || Z_TYPE_P(op_2) == IS_OBJECT) { + ret = zend_equals_object(op_1, op_2, ZEND_IS_EQUAL); + } else { + ret = zend_compare(op_1, op_2); + } if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { zval_ptr_dtor_nogc(op_1); } @@ -581,7 +585,11 @@ ZEND_VM_HELPER(zend_is_not_equal_helper, ANY, ANY, zval *op_1, zval *op_2) if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { op_2 = ZVAL_UNDEFINED_OP2(); } - ret = zend_compare(op_1, op_2); + if (Z_TYPE_P(op_1) == IS_OBJECT || Z_TYPE_P(op_2) == IS_OBJECT) { + ret = zend_equals_object(op_1, op_2, ZEND_IS_NOT_EQUAL); + } else { + ret = zend_compare(op_1, op_2); + } if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { zval_ptr_dtor_nogc(op_1); } From 2fa61555e0ace5f478505bee080402c8144ebbf2 Mon Sep 17 00:00:00 2001 From: Jordan LeDoux Date: Wed, 19 Jan 2022 16:22:48 -0800 Subject: [PATCH 2/5] Added fallthrough for == operator with objects for extensions --- Zend/zend_operators.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index f90181b21ee8a..ec540a596e4a7 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2137,7 +2137,6 @@ ZEND_API int ZEND_FASTCALL zend_equals_object(zval *op1, zval *op2, zend_uchar e zval ret; int retVal; int result; - zend_function *op_handler; if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_P(op1) == Z_OBJ_P(op2)) { From 2be20775194e7c2518e1a3e28641d26ebe59ae6e Mon Sep 17 00:00:00 2001 From: Jordan LeDoux Date: Thu, 20 Jan 2022 09:55:39 -0800 Subject: [PATCH 3/5] Fixed looping bug in zend_equals_object --- Zend/zend_operators.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index ec540a596e4a7..2d90e9f13886f 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2168,11 +2168,7 @@ ZEND_API int ZEND_FASTCALL zend_equals_object(zval *op1, zval *op2, zend_uchar e } return retVal; } else { - if (Z_TYPE_P(op2) == IS_OBJECT) { - goto op2_equals_handler; - } else { - goto default_equals_handler; - } + goto default_equals_handler; } } else { default_equals_handler: From c6440fa0971d2ddc6f725e75808ce6b96059a863 Mon Sep 17 00:00:00 2001 From: Jordan LeDoux Date: Sat, 14 May 2022 08:24:08 -0700 Subject: [PATCH 4/5] Switching to a new handler based implementation --- Zend/zend_iterators.c | 3 ++- Zend/zend_object_handlers.c | 5 +++++ Zend/zend_object_handlers.h | 3 +++ Zend/zend_operators.c | 8 ++++---- ext/com_dotnet/com_handlers.c | 1 + ext/com_dotnet/com_saproxy.c | 1 + 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Zend/zend_iterators.c b/Zend/zend_iterators.c index aa4391f2caa99..ecc06bd4ca751 100644 --- a/Zend/zend_iterators.c +++ b/Zend/zend_iterators.c @@ -51,7 +51,8 @@ static const zend_object_handlers iterator_object_handlers = { iter_wrapper_get_gc, NULL, /* do_operation */ NULL, /* compare */ - NULL /* get_properties_for */ + NULL, /* get_properties_for */ + NULL /* equals */ }; ZEND_API void zend_register_iterator_wrapper(void) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 746897f641e0e..5b9ecfffc0440 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1941,6 +1941,10 @@ ZEND_API HashTable *zend_get_properties_for(zval *obj, zend_prop_purpose purpose return zend_std_get_properties_for(zobj, purpose); } +ZEND_API zend_result zend_std_equals_objects(zend_uchar opcode, zval *result, zval *op1, zval *op2) { + return FAILURE; +} + ZEND_API const zend_object_handlers std_object_handlers = { 0, /* offset */ @@ -1969,4 +1973,5 @@ ZEND_API const zend_object_handlers std_object_handlers = { NULL, /* do_operation */ zend_std_compare_objects, /* compare */ NULL, /* get_properties_for */ + zend_std_equals_objects, /* equals */ }; diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 53eef829282ce..66c6a8a00d822 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -156,6 +156,8 @@ typedef HashTable *(*zend_object_get_gc_t)(zend_object *object, zval **table, in typedef int (*zend_object_do_operation_t)(zend_uchar opcode, zval *result, zval *op1, zval *op2); +typedef zend_result (*zend_object_equals_t)(zend_uchar opcode, zval *result, zval *op1, zval *op2); + struct _zend_object_handlers { /* offset of real object header (usually zero) */ int offset; @@ -184,6 +186,7 @@ struct _zend_object_handlers { zend_object_do_operation_t do_operation; /* optional */ zend_object_compare_t compare; /* required */ zend_object_get_properties_for_t get_properties_for; /* optional */ + zend_object_equals_t equals; /* optional */ }; BEGIN_EXTERN_C() diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index a00cd2f6f51ea..ddccc9d8baa2a 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2142,8 +2142,8 @@ ZEND_API int ZEND_FASTCALL zend_equals_object(zval *op1, zval *op2, zend_uchar e Z_OBJ_P(op1) == Z_OBJ_P(op2)) { return 0; } else if (Z_TYPE_P(op1) == IS_OBJECT) { - if (Z_OBJ_HANDLER_P(op1, do_operation)) { - result = Z_OBJ_HANDLER_P(op1, do_operation)(equals, &ret, op1, op2); + if (Z_OBJ_HANDLER_P(op1, equals)) { + result = Z_OBJ_HANDLER_P(op1, equals)(equals, &ret, op1, op2); if (result == FAILURE) { goto op2_equals_handler; } else { @@ -2159,8 +2159,8 @@ ZEND_API int ZEND_FASTCALL zend_equals_object(zval *op1, zval *op2, zend_uchar e } } else if (Z_TYPE_P(op2) == IS_OBJECT) { op2_equals_handler: - if (Z_OBJ_HANDLER_P(op2, do_operation)) { - result = Z_OBJ_HANDLER_P(op2, do_operation)(equals, &ret, op1, op2); + if (Z_OBJ_HANDLER_P(op2, equals)) { + result = Z_OBJ_HANDLER_P(op2, equals)(equals, &ret, op1, op2); if (result == FAILURE) { goto default_equals_handler; } else { diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index fe1b6f257b283..53f1ab5a914b3 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -531,6 +531,7 @@ zend_object_handlers php_com_object_handlers = { NULL, /* do_operation */ com_objects_compare, /* compare */ NULL, /* get_properties_for */ + zend_std_equals_objects, /* equals */ }; void php_com_object_enable_event_sink(php_com_dotnet_object *obj, bool enable) diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c index 4e19f6e78e5d2..677c44f8b8889 100644 --- a/ext/com_dotnet/com_saproxy.c +++ b/ext/com_dotnet/com_saproxy.c @@ -413,6 +413,7 @@ zend_object_handlers php_com_saproxy_handlers = { NULL, /* do_operation */ saproxy_objects_compare, /* compare */ NULL, /* get_properties_for */ + zend_std_equals_objects, /* equals */ }; void php_com_saproxy_create(zend_object *com_object, zval *proxy_out, zval *index) From 8a2b6cdbfe432d221e4e6e0414db33fa1f169da2 Mon Sep 17 00:00:00 2001 From: Jordan LeDoux Date: Sat, 14 May 2022 08:52:21 -0700 Subject: [PATCH 5/5] Fixing broken compile --- ext/com_dotnet/com_handlers.c | 2 +- ext/com_dotnet/com_saproxy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 53f1ab5a914b3..f3821d82d67ca 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -531,7 +531,7 @@ zend_object_handlers php_com_object_handlers = { NULL, /* do_operation */ com_objects_compare, /* compare */ NULL, /* get_properties_for */ - zend_std_equals_objects, /* equals */ + NULL, /* equals */ }; void php_com_object_enable_event_sink(php_com_dotnet_object *obj, bool enable) diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c index 677c44f8b8889..960f126a70f8f 100644 --- a/ext/com_dotnet/com_saproxy.c +++ b/ext/com_dotnet/com_saproxy.c @@ -413,7 +413,7 @@ zend_object_handlers php_com_saproxy_handlers = { NULL, /* do_operation */ saproxy_objects_compare, /* compare */ NULL, /* get_properties_for */ - zend_std_equals_objects, /* equals */ + NULL, /* equals */ }; void php_com_saproxy_create(zend_object *com_object, zval *proxy_out, zval *index)