Fix persistent XML memory leaks in SOAP

SOAP uses a horrible bailout based error handling approach -- avoid
leaking persistent XML memory by catching bailouts in a number of
places.
This commit is contained in:
Nikita Popov 2019-06-27 10:57:49 +02:00
parent cfeda978df
commit 78375aa52f
3 changed files with 46 additions and 8 deletions

View file

@ -1519,7 +1519,13 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z
text = xmlNewText(BAD_CAST(str_val)); text = xmlNewText(BAD_CAST(str_val));
xmlAddChild(dummy, text); xmlAddChild(dummy, text);
ZVAL_NULL(&data); ZVAL_NULL(&data);
master_to_zval(&data, attr->encode, dummy); /* TODO: There are other places using dummy nodes -- generalize? */
zend_try {
master_to_zval(&data, attr->encode, dummy);
} zend_catch {
xmlFreeNode(dummy);
zend_bailout();
} zend_end_try();
xmlFreeNode(dummy); xmlFreeNode(dummy);
set_zval_property(ret, attr->name, &data); set_zval_property(ret, attr->name, &data);
} }

View file

@ -739,7 +739,9 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
zend_hash_init(&ctx.portTypes, 0, NULL, NULL, 0); zend_hash_init(&ctx.portTypes, 0, NULL, NULL, 0);
zend_hash_init(&ctx.services, 0, NULL, NULL, 0); zend_hash_init(&ctx.services, 0, NULL, NULL, 0);
load_wsdl_ex(this_ptr, struri,&ctx, 0); load_wsdl_ex(this_ptr, struri, &ctx, 0);
zend_try {
schema_pass2(&ctx); schema_pass2(&ctx);
n = zend_hash_num_elements(&ctx.services); n = zend_hash_num_elements(&ctx.services);
@ -1166,6 +1168,12 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri)
soap_error0(E_ERROR, "Parsing WSDL: Could not find any usable binding services in WSDL."); soap_error0(E_ERROR, "Parsing WSDL: Could not find any usable binding services in WSDL.");
} }
} zend_catch {
/* Avoid persistent memory leak. */
zend_hash_destroy(&ctx.docs);
zend_bailout();
} zend_end_try();
zend_hash_destroy(&ctx.messages); zend_hash_destroy(&ctx.messages);
zend_hash_destroy(&ctx.bindings); zend_hash_destroy(&ctx.bindings);
zend_hash_destroy(&ctx.portTypes); zend_hash_destroy(&ctx.portTypes);

View file

@ -1643,7 +1643,15 @@ PHP_METHOD(SoapServer, handle)
old_features = SOAP_GLOBAL(features); old_features = SOAP_GLOBAL(features);
SOAP_GLOBAL(features) = service->features; SOAP_GLOBAL(features) = service->features;
old_soap_version = SOAP_GLOBAL(soap_version); old_soap_version = SOAP_GLOBAL(soap_version);
function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &soap_version, &soap_headers);
zend_try {
function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &soap_version, &soap_headers);
} zend_catch {
/* Avoid leaking persistent memory */
xmlFreeDoc(doc_request);
zend_bailout();
} zend_end_try();
xmlFreeDoc(doc_request); xmlFreeDoc(doc_request);
if (EG(exception)) { if (EG(exception)) {
@ -3821,6 +3829,8 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function
encode_reset_ns(); encode_reset_ns();
doc = xmlNewDoc(BAD_CAST("1.0")); doc = xmlNewDoc(BAD_CAST("1.0"));
zend_try {
doc->charset = XML_CHAR_ENCODING_UTF8; doc->charset = XML_CHAR_ENCODING_UTF8;
doc->encoding = xmlCharStrdup("UTF-8"); doc->encoding = xmlCharStrdup("UTF-8");
@ -4162,6 +4172,12 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function
encode_finish(); encode_finish();
} zend_catch {
/* Avoid persistent memory leak. */
xmlFreeDoc(doc);
zend_bailout();
} zend_end_try();
if (function && function->responseName == NULL && if (function && function->responseName == NULL &&
body->children == NULL && head == NULL) { body->children == NULL && head == NULL) {
xmlFreeDoc(doc); xmlFreeDoc(doc);
@ -4183,6 +4199,8 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function
encode_reset_ns(); encode_reset_ns();
doc = xmlNewDoc(BAD_CAST("1.0")); doc = xmlNewDoc(BAD_CAST("1.0"));
zend_try {
doc->encoding = xmlCharStrdup("UTF-8"); doc->encoding = xmlCharStrdup("UTF-8");
doc->charset = XML_CHAR_ENCODING_UTF8; doc->charset = XML_CHAR_ENCODING_UTF8;
if (version == SOAP_1_1) { if (version == SOAP_1_1) {
@ -4222,7 +4240,7 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function
} }
} else { } else {
if ((zstyle = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "style", sizeof("style")-1)) != NULL && if ((zstyle = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "style", sizeof("style")-1)) != NULL &&
Z_TYPE_P(zstyle) == IS_LONG) { Z_TYPE_P(zstyle) == IS_LONG) {
style = Z_LVAL_P(zstyle); style = Z_LVAL_P(zstyle);
} else { } else {
style = SOAP_RPC; style = SOAP_RPC;
@ -4245,7 +4263,7 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function
} }
if ((zuse = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "use", sizeof("use")-1)) != NULL && if ((zuse = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "use", sizeof("use")-1)) != NULL &&
Z_TYPE_P(zuse) == IS_LONG && Z_LVAL_P(zuse) == SOAP_LITERAL) { Z_TYPE_P(zuse) == IS_LONG && Z_LVAL_P(zuse) == SOAP_LITERAL) {
use = SOAP_LITERAL; use = SOAP_LITERAL;
} else { } else {
use = SOAP_ENCODED; use = SOAP_ENCODED;
@ -4307,9 +4325,9 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function
ht = Z_OBJPROP_P(header); ht = Z_OBJPROP_P(header);
if ((name = zend_hash_str_find(ht, "name", sizeof("name")-1)) != NULL && if ((name = zend_hash_str_find(ht, "name", sizeof("name")-1)) != NULL &&
Z_TYPE_P(name) == IS_STRING && Z_TYPE_P(name) == IS_STRING &&
(ns = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL && (ns = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL &&
Z_TYPE_P(ns) == IS_STRING) { Z_TYPE_P(ns) == IS_STRING) {
xmlNodePtr h; xmlNodePtr h;
xmlNsPtr nsptr; xmlNsPtr nsptr;
int hdr_use = SOAP_LITERAL; int hdr_use = SOAP_LITERAL;
@ -4362,6 +4380,12 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function
encode_finish(); encode_finish();
} zend_catch {
/* Avoid persistent memory leak. */
xmlFreeDoc(doc);
zend_bailout();
} zend_end_try();
return doc; return doc;
} }
/* }}} */ /* }}} */