From e9779adab821b23bc20a43d20a38d9bc84fe596c Mon Sep 17 00:00:00 2001 From: Valery Ivashchanka Date: Fri, 16 Oct 2026 01:35:04 +0000 Subject: [PATCH] Fix SoapClient writing to output headers after an exception When decoding a response header threw an exception, for example from a typemap "from_xml" callback, parse_packet_soap() went on decoding the remaining headers and adding them to the output headers array. The trace of the exception holds a copy of that array (the argument of __soapCall()), so the array is shared: a debug build fails with an assertion in _zend_hash_str_add_or_update_i(), and a release build changes the array that the trace shows. Stop decoding the headers once an exception is pending. The headers decoded before it stay in the output array. Co-Authored-By: Claude Opus 5.5 --- NEWS | 3 + ext/soap/php_packet_soap.c | 5 ++ ext/soap/tests/output_headers_exception.phpt | 64 ++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 ext/soap/tests/output_headers_exception.phpt diff --git a/NEWS b/NEWS index c695f56584c9..ac76124e507f 100644 --- a/NEWS +++ b/NEWS @@ -77,6 +77,9 @@ PHP NEWS - SOAP: . Fixed use of uninitialized func in do_request() on OOM bailout. (David Carlier) + . Fixed SoapClient writing to the output headers array, which the exception + trace shares, after decoding a response header threw an exception. + (Valery Ivashchanka) - Session: . Fixed session data loss in the files save handler when writing the session diff --git a/ext/soap/php_packet_soap.c b/ext/soap/php_packet_soap.c index 7dcd56f34cce..291dd20271fe 100644 --- a/ext/soap/php_packet_soap.c +++ b/ext/soap/php_packet_soap.c @@ -435,6 +435,11 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio smart_str_free(&key); } master_to_zval_with_doc_cleanup(&val, enc, trav, response); + if (EG(exception)) { + /* The trace of the exception holds a copy of the output headers array */ + zval_ptr_dtor(&val); + break; + } add_assoc_zval(soap_headers, (char*)trav->name, &val); } trav = trav->next; diff --git a/ext/soap/tests/output_headers_exception.phpt b/ext/soap/tests/output_headers_exception.phpt new file mode 100644 index 000000000000..e74a5286504f --- /dev/null +++ b/ext/soap/tests/output_headers_exception.phpt @@ -0,0 +1,64 @@ +--TEST-- +SoapClient stops decoding response headers after an exception +--EXTENSIONS-- +soap +--INI-- +zend.exception_ignore_args=0 +--FILE-- + + + +

1

+

a

+

3

+
+ + + 1 + + +
+XML; + } +} + +function string_from_xml($xml) { + throw new Exception("string_from_xml failed"); +} + +$client = new TestSoapClient(null, [ + 'location' => 'test://', + 'uri' => 'urn:test', + 'typemap' => [[ + 'type_ns' => 'http://www.w3.org/2001/XMLSchema', + 'type_name' => 'string', + 'from_xml' => 'string_from_xml', + ]], +]); + +$headers = []; +try { + $client->__soapCall('test', [], null, null, $headers); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; + // The trace holds the output headers as they were when the exception was thrown + var_dump($e->getTrace()[1]['args'][4]); +} +var_dump($headers); +?> +--EXPECT-- +string_from_xml failed +array(1) { + ["h1"]=> + int(1) +} +array(1) { + ["h1"]=> + int(1) +}