From 23912f55eb2c4b3d2032e9bc49ea8231df08e96e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 30 May 2024 23:41:56 +0200 Subject: [PATCH] Fix memory leak if calling SoapServer::setClass() twice Closes GH-14381. --- NEWS | 1 + ext/soap/soap.c | 21 ++++++++++++++------- ext/soap/tests/bugs/setClass_twice.phpt | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 ext/soap/tests/bugs/setClass_twice.phpt diff --git a/NEWS b/NEWS index e13d1a6c03f..0091640a2d5 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,7 @@ PHP NEWS . Fixed bug #47925 (PHPClient can't decompress response). (nielsdos) . Fix missing error restore code. (nielsdos) . Fix memory leak if calling SoapServer::setObject() twice. (nielsdos) + . Fix memory leak if calling SoapServer::setClass() twice. (nielsdos) - Sodium: . Fix memory leaks in ext/sodium on failure of some functions. (nielsdos) diff --git a/ext/soap/soap.c b/ext/soap/soap.c index a64509479b4..809935f57d8 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -66,6 +66,7 @@ static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, static void delete_service(void *service); static void delete_url(void *handle); static void delete_hashtable(void *hashtable); +static void delete_argv(struct _soap_class *class); static void soap_error_handler(int error_num, zend_string *error_filename, const uint32_t error_lineno, zend_string *message); @@ -928,6 +929,8 @@ PHP_METHOD(SoapServer, setClass) service->type = SOAP_CLASS; service->soap_class.ce = ce; + delete_argv(&service->soap_class); + service->soap_class.persistence = SOAP_PERSISTENCE_REQUEST; service->soap_class.argc = num_args; if (service->soap_class.argc > 0) { @@ -4347,6 +4350,16 @@ static void delete_url(void *handle) /* {{{ */ } /* }}} */ +static void delete_argv(struct _soap_class *class) +{ + if (class->argc) { + for (int i = 0; i < class->argc; i++) { + zval_ptr_dtor(&class->argv[i]); + } + efree(class->argv); + } +} + static void delete_service(void *data) /* {{{ */ { soapServicePtr service = (soapServicePtr)data; @@ -4361,13 +4374,7 @@ static void delete_service(void *data) /* {{{ */ efree(service->typemap); } - if (service->soap_class.argc) { - int i; - for (i = 0; i < service->soap_class.argc;i++) { - zval_ptr_dtor(&service->soap_class.argv[i]); - } - efree(service->soap_class.argv); - } + delete_argv(&service->soap_class); if (service->actor) { efree(service->actor); diff --git a/ext/soap/tests/bugs/setClass_twice.phpt b/ext/soap/tests/bugs/setClass_twice.phpt new file mode 100644 index 00000000000..0651e2dbec2 --- /dev/null +++ b/ext/soap/tests/bugs/setClass_twice.phpt @@ -0,0 +1,20 @@ +--TEST-- +SOAP Server: SoapServer::setClass() twice +--EXTENSIONS-- +soap +--FILE-- +"http://testuri.org")); +$server->setClass(Foo::class, new stdClass, []); +$server->setClass(Foo::class, new stdClass, []); + +echo "Done\n"; +?> +--EXPECT-- +Done