Commit 3589066c7c0 for php

commit 3589066c7c0e0534d87925df3941045578fcaab1
Author: lazerg <lazerg2@gmail.com>
Date:   Thu Nov 12 18:39:55 2026 +0000

    Fix GH-25094: NULL dereference in SOAP get_doc_function() with missing parts

    In document style, get_doc_function() walks the request Body elements
    alongside the WSDL parts, but it never checks whether it ran out of elements.
    When the Body has fewer elements than the operation declares, node becomes
    NULL and the next part comparison dereferences it. Now it treats that as no
    match, so the request gets the same "Procedure not present" fault as any
    other mismatch.

    Close GH-25101

diff --git a/NEWS b/NEWS
index b5dbe65a83c..4299e2d5fe2 100644
--- a/NEWS
+++ b/NEWS
@@ -83,6 +83,8 @@ PHP                                                                        NEWS
 - SOAP:
   . Fixed bug GH-25267 (NULL dereference in to_xml_any() with integer key).
     (lazerg)
+  . Fixed bug GH-25094 (NULL dereference in get_doc_function() with missing
+    parts). (lazerg)

 - Readline:
   . Fixed incorrect handling of non-ASCII pending_input bytes in readline_info(),
diff --git a/ext/soap/soap.c b/ext/soap/soap.c
index eb35cfc7265..3bba56782f3 100644
--- a/ext/soap/soap.c
+++ b/ext/soap/soap.c
@@ -4284,6 +4284,10 @@ static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr params) /* {{{ */
 						xmlNodePtr node = params;

 						ZEND_HASH_FOREACH_PTR(tmp->requestParameters, param) {
+							if (node == NULL) {
+								ok = 0;
+								break;
+							}
 							if (param->element) {
 								if (strcmp(param->element->name, (char*)node->name) != 0) {
 									ok = 0;
diff --git a/ext/soap/tests/gh25094.phpt b/ext/soap/tests/gh25094.phpt
new file mode 100644
index 00000000000..59ad67d8789
--- /dev/null
+++ b/ext/soap/tests/gh25094.phpt
@@ -0,0 +1,29 @@
+--TEST--
+GH-25094 (NULL pointer dereference in get_doc_function() when the request has fewer parts than the WSDL)
+--CREDITS--
+cxxz16
+--EXTENSIONS--
+soap
+--INI--
+soap.wsdl_cache_enabled=0
+--FILE--
+<?php
+class TestService {
+    public function Test($a, $b) {
+        return $a;
+    }
+}
+
+$server = new SoapServer(__DIR__ . '/gh25094.wsdl');
+$server->setClass('TestService');
+
+$server->handle(<<<'XML'
+<?xml version="1.0"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://test-uri">
+  <SOAP-ENV:Body><tns:a>foo</tns:a></SOAP-ENV:Body>
+</SOAP-ENV:Envelope>
+XML);
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Procedure 'a' not present</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
diff --git a/ext/soap/tests/gh25094.wsdl b/ext/soap/tests/gh25094.wsdl
new file mode 100644
index 00000000000..b7865b2db58
--- /dev/null
+++ b/ext/soap/tests/gh25094.wsdl
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
+             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+             xmlns:tns="http://test-uri"
+             targetNamespace="http://test-uri">
+  <types>
+    <xsd:schema targetNamespace="http://test-uri" elementFormDefault="qualified">
+      <xsd:element name="a" type="xsd:string"/>
+      <xsd:element name="b" type="xsd:string"/>
+    </xsd:schema>
+  </types>
+  <message name="TestRequest">
+    <part name="a" element="tns:a"/>
+    <part name="b" element="tns:b"/>
+  </message>
+  <message name="TestResponse">
+    <part name="r" element="tns:a"/>
+  </message>
+  <portType name="TestPortType">
+    <operation name="Test">
+      <input message="tns:TestRequest"/>
+      <output message="tns:TestResponse"/>
+    </operation>
+  </portType>
+  <binding name="TestBinding" type="tns:TestPortType">
+    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+    <operation name="Test">
+      <soap:operation soapAction="http://test-uri/Test"/>
+      <input><soap:body use="literal"/></input>
+      <output><soap:body use="literal"/></output>
+    </operation>
+  </binding>
+  <service name="TestService">
+    <port name="TestPort" binding="tns:TestBinding">
+      <soap:address location="http://localhost/test"/>
+    </port>
+  </service>
+</definitions>