diff --git a/UPGRADING b/UPGRADING index 89acb2d25884b..ef6a44bf6e706 100644 --- a/UPGRADING +++ b/UPGRADING @@ -138,6 +138,8 @@ PHP 8.4 UPGRADE NOTES - SOAP: . SoapClient::$httpurl is now a Soap\Url object rather than a resource. Value checks using is_resource() should be replaced with checks for `null`. + . SoapClient::$sdl is now a Soap\Sdl object rather than a resource. + Value checks using is_resource() should be replaced with checks for `null`. - SPL: . Out of bounds accesses in SplFixedArray now throw an exception of type diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index e1961a05e38c1..4215d07c853ef 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -3449,12 +3449,10 @@ void delete_sdl_impl(void *handle) efree(tmp); } -void delete_sdl(void *handle) +void delete_sdl(sdl *handle) { - sdlPtr tmp = (sdlPtr)handle; - - if (!tmp->is_persistent) { - delete_sdl_impl(tmp); + if (!handle->is_persistent) { + delete_sdl_impl(handle); } } diff --git a/ext/soap/php_sdl.h b/ext/soap/php_sdl.h index 08f3923698011..3a1bcb51a8af6 100644 --- a/ext/soap/php_sdl.h +++ b/ext/soap/php_sdl.h @@ -260,7 +260,7 @@ encodePtr get_encoder_ex(sdlPtr sdl, const char *nscat, int len); sdlBindingPtr get_binding_from_type(sdlPtr sdl, sdlBindingType type); sdlBindingPtr get_binding_from_name(sdlPtr sdl, char *name, char *ns); -void delete_sdl(void *handle); +void delete_sdl(sdl *handle); void delete_sdl_impl(void *handle); void sdl_set_uri_credentials(sdlCtx *ctx, char *uri); diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index 83dda56e6ba76..3d9ccf330300a 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -193,6 +193,7 @@ ZEND_TSRMLS_CACHE_EXTERN() extern zend_class_entry* soap_class_entry; extern zend_class_entry* soap_var_class_entry; extern zend_class_entry* soap_url_class_entry; +extern zend_class_entry* soap_sdl_class_entry; void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); @@ -263,4 +264,10 @@ static inline soap_url_object *soap_url_object_fetch(zend_object *obj) } #define Z_SOAP_URL_P(zv) soap_url_object_fetch(Z_OBJ_P(zv)) + +typedef struct soap_sdl_object { + sdl *sdl; + zend_object std; +} soap_sdl_object; + #endif diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 7584cc5756e01..8b3f20f3f5140 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -29,7 +29,6 @@ #include "ext/standard/php_incomplete_class.h" -static int le_sdl = 0; static int le_typemap = 0; typedef struct _soapHeader { @@ -128,15 +127,13 @@ static void soap_error_handler(int error_num, zend_string *error_filename, const #define FETCH_THIS_SDL(ss) \ { \ zval *__tmp = Z_CLIENT_SDL_P(ZEND_THIS); \ - if (Z_TYPE_P(__tmp) == IS_RESOURCE) { \ - FETCH_SDL_RES(ss,__tmp); \ + if (Z_TYPE_P(__tmp) == IS_OBJECT && instanceof_function(Z_OBJCE_P(__tmp), soap_sdl_class_entry)) { \ + ss = Z_SOAP_SDL_P(__tmp)->sdl; \ } else { \ ss = NULL; \ } \ } -#define FETCH_SDL_RES(ss,tmp) ss = (sdlPtr) zend_fetch_resource_ex(tmp, "sdl", le_sdl) - #define FETCH_TYPEMAP_RES(ss,tmp) ss = (HashTable*) zend_fetch_resource_ex(tmp, "typemap", le_typemap) #define Z_PARAM_NAME_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 0)) @@ -177,9 +174,11 @@ static zend_class_entry* soap_header_class_entry; static zend_class_entry* soap_param_class_entry; zend_class_entry* soap_var_class_entry; zend_class_entry *soap_url_class_entry; +zend_class_entry *soap_sdl_class_entry; static zend_object_handlers soap_server_object_handlers; static zend_object_handlers soap_url_object_handlers; +static zend_object_handlers soap_sdl_object_handlers; typedef struct { soapServicePtr service; @@ -234,6 +233,43 @@ static zend_function *soap_url_object_get_constructor(zend_object *object) return NULL; } + +static inline soap_sdl_object *soap_sdl_object_fetch(zend_object *obj) +{ + return (soap_sdl_object *) ((char *) obj - XtOffsetOf(soap_sdl_object, std)); +} + +#define Z_SOAP_SDL_P(zv) soap_sdl_object_fetch(Z_OBJ_P(zv)) + +static zend_object *soap_sdl_object_create(zend_class_entry *ce) +{ + soap_sdl_object *sdl_obj = zend_object_alloc(sizeof(soap_sdl_object), ce); + + zend_object_std_init(&sdl_obj->std, ce); + object_properties_init(&sdl_obj->std, ce); + + return &sdl_obj->std; +} + +static void soap_sdl_object_free(zend_object *obj) +{ + soap_sdl_object *sdl_obj = soap_sdl_object_fetch(obj); + + if (sdl_obj->sdl) { + delete_sdl(sdl_obj->sdl); + sdl_obj->sdl = NULL; + } + + zend_object_std_dtor(&sdl_obj->std); +} + +static zend_function *soap_sdl_object_get_constructor(zend_object *object) +{ + zend_throw_error(NULL, "Cannot directly construct Soap\\Sdl"); + + return NULL; +} + ZEND_DECLARE_MODULE_GLOBALS(soap) static void (*old_error_handler)(int, zend_string *, const uint32_t, zend_string *); @@ -418,11 +454,6 @@ PHP_RINIT_FUNCTION(soap) return SUCCESS; } -static void delete_sdl_res(zend_resource *res) -{ - delete_sdl(res->ptr); -} - static void delete_hashtable_res(zend_resource *res) { delete_hashtable(res->ptr); @@ -458,7 +489,6 @@ PHP_MINIT_FUNCTION(soap) soap_header_class_entry = register_class_SoapHeader(); - le_sdl = zend_register_list_destructors_ex(delete_sdl_res, NULL, "SOAP SDL", module_number); le_typemap = zend_register_list_destructors_ex(delete_hashtable_res, NULL, "SOAP table", module_number); soap_url_class_entry = register_class_Soap_Url(); @@ -472,6 +502,17 @@ PHP_MINIT_FUNCTION(soap) soap_url_object_handlers.clone_obj = NULL; soap_url_object_handlers.compare = zend_objects_not_comparable; + soap_sdl_class_entry = register_class_Soap_Sdl(); + soap_sdl_class_entry->create_object = soap_sdl_object_create; + soap_sdl_class_entry->default_object_handlers = &soap_sdl_object_handlers; + + memcpy(&soap_sdl_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + soap_sdl_object_handlers.offset = XtOffsetOf(soap_sdl_object, std); + soap_sdl_object_handlers.free_obj = soap_sdl_object_free; + soap_sdl_object_handlers.get_constructor = soap_sdl_object_get_constructor; + soap_sdl_object_handlers.clone_obj = NULL; + soap_sdl_object_handlers.compare = zend_objects_not_comparable; + register_soap_symbols(module_number); old_error_handler = zend_error_cb; @@ -2086,15 +2127,20 @@ PHP_METHOD(SoapClient, __construct) if (wsdl) { int old_soap_version; - zend_resource *res; old_soap_version = SOAP_GLOBAL(soap_version); SOAP_GLOBAL(soap_version) = soap_version; sdl = get_sdl(this_ptr, ZSTR_VAL(wsdl), cache_wsdl); - res = zend_register_resource(sdl, le_sdl); - ZVAL_RES(Z_CLIENT_SDL_P(this_ptr), res); + zval *sdl_zval = Z_CLIENT_SDL_P(this_ptr); + if (Z_TYPE_P(sdl_zval) == IS_OBJECT) { + zval_ptr_dtor(sdl_zval); + } + + object_init_ex(sdl_zval, soap_sdl_class_entry); + soap_sdl_object *sdl_object = Z_SOAP_SDL_P(sdl_zval); + sdl_object->sdl = sdl; SOAP_GLOBAL(soap_version) = old_soap_version; } @@ -2227,8 +2273,11 @@ static void do_soap_call(zend_execute_data *execute_data, } tmp = Z_CLIENT_SDL_P(this_ptr); - if (Z_TYPE_P(tmp) == IS_RESOURCE) { - FETCH_SDL_RES(sdl,tmp); + if (Z_TYPE_P(tmp) == IS_OBJECT) { +#ifdef ZEND_DEBUG + ZEND_ASSERT(instanceof_function(Z_OBJCE_P(tmp), soap_sdl_class_entry)); +#endif + sdl = Z_SOAP_SDL_P(tmp)->sdl; } tmp = Z_CLIENT_TYPEMAP_P(this_ptr); @@ -2536,14 +2585,13 @@ PHP_METHOD(SoapClient, __soapCall) /* {{{ Returns list of SOAP functions */ PHP_METHOD(SoapClient, __getFunctions) { - sdlPtr sdl; - - FETCH_THIS_SDL(sdl); - if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } + sdl *sdl; + FETCH_THIS_SDL(sdl); + if (sdl) { smart_str buf = {0}; sdlFunctionPtr function; @@ -2562,14 +2610,13 @@ PHP_METHOD(SoapClient, __getFunctions) /* {{{ Returns list of SOAP types */ PHP_METHOD(SoapClient, __getTypes) { - sdlPtr sdl; - - FETCH_THIS_SDL(sdl); - if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } + sdl *sdl; + FETCH_THIS_SDL(sdl); + if (sdl) { sdlTypePtr type; smart_str buf = {0}; diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index c23b21c0f498b..fca82d993d20b 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -10,6 +10,14 @@ final class Url { } + + /** + * @strict-properties + * @not-serializable + */ + final class Sdl + { + } } namespace { @@ -528,8 +536,7 @@ class SoapClient private ?string $location = null; private bool $trace = false; private ?int $compression = null; - /** @var resource|null */ - private $sdl = null; + private ?Soap\Sdl $sdl = null; /** @var resource|null */ private $typemap = null; /** @var resource|null */ diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index c4df10ab8aa7c..fc9d567d26cae 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 038c8f9ba355fba63e661148b48cdf0299b922f6 */ + * Stub hash: 70fce84457c1e8fc45832d1fa6e7e070c67ad03f */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true") @@ -177,6 +177,10 @@ static const zend_function_entry class_Soap_Url_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_Soap_Sdl_methods[] = { + ZEND_FE_END +}; + static const zend_function_entry class_SoapParam_methods[] = { ZEND_ME(SoapParam, __construct, arginfo_class_SoapParam___construct, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -325,6 +329,17 @@ static zend_class_entry *register_class_Soap_Url(void) return class_entry; } +static zend_class_entry *register_class_Soap_Sdl(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Soap", "Sdl", class_Soap_Sdl_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; + + return class_entry; +} + static zend_class_entry *register_class_SoapParam(void) { zend_class_entry ce, *class_entry; @@ -548,7 +563,8 @@ static zend_class_entry *register_class_SoapClient(void) zval property_sdl_default_value; ZVAL_NULL(&property_sdl_default_value); zend_string *property_sdl_name = zend_string_init("sdl", sizeof("sdl") - 1, 1); - zend_declare_typed_property(class_entry, property_sdl_name, &property_sdl_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_NONE(0)); + zend_string *property_sdl_class_Soap_Sdl = zend_string_init("Soap\\Sdl", sizeof("Soap\\Sdl")-1, 1); + zend_declare_typed_property(class_entry, property_sdl_name, &property_sdl_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_sdl_class_Soap_Sdl, 0, MAY_BE_NULL)); zend_string_release(property_sdl_name); zval property_typemap_default_value;