diff --git a/.github/scripts/windows/test_task.bat b/.github/scripts/windows/test_task.bat
index 7c526be95c3d..6c49ebe40417 100644
--- a/.github/scripts/windows/test_task.bat
+++ b/.github/scripts/windows/test_task.bat
@@ -117,8 +117,9 @@ set PHP_BUILD_DIR=%PHP_BUILD_OBJ_DIR%\Release
if "%THREAD_SAFE%" equ "1" set PHP_BUILD_DIR=%PHP_BUILD_DIR%_TS
rem prepare for mail
-curl -sLo hMailServer.exe https://www.hmailserver.com/download_file/?downloadid=271
-hMailServer.exe /verysilent
+curl -sLo hMailServer.zip https://downloads.php.net/~windows/php-sdk/deps/vs18/x64/hmailserver-5.7.0-vs18-x64.zip
+unzip -q hMailServer.zip -d hMailServer
+hMailServer\bin\hMailServer.exe /verysilent
cd %APPVEYOR_BUILD_FOLDER%
%PHP_BUILD_DIR%\php.exe -dextension_dir=%PHP_BUILD_DIR% -dextension=com_dotnet .github\setup_hmailserver.php
diff --git a/NEWS b/NEWS
index 378643836c80..9ce1698bce56 100644
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,14 @@ PHP NEWS
. Fixed segfault in ReflectionMethod::createFromMethodName() on an
uninstantiable subclass. (iliaal)
+- Session:
+ . Fix corruption in mod_mm. (ndossche)
+ . Fixed bug GH-23043 (broken session id code can cause zend_mm_heap
+ corrupted). (ndossche)
+
+- SimpleXML:
+ . Fixed negative element offsets aliasing the first element. (iliaal)
+
- Sockets:
. Fixed various memory related issues in ext/sockets. (David Carlier)
diff --git a/ext/session/mod_mm.c b/ext/session/mod_mm.c
index b997a2bdcff5..75ee713e9f09 100644
--- a/ext/session/mod_mm.c
+++ b/ext/session/mod_mm.c
@@ -351,7 +351,7 @@ PS_READ_FUNC(mm)
&& ps_mm_key_exists(data, key) == FAILURE) {
/* key points to PS(id), but cannot change here. */
if (key) {
- efree(PS(id));
+ zend_string_release_ex(PS(id), false);
PS(id) = NULL;
}
PS(id) = PS(mod)->s_create_sid((void **)&data);
diff --git a/ext/session/session.c b/ext/session/session.c
index ba71d709a536..6380505ae951 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -443,6 +443,7 @@ static zend_result php_session_initialize(void) /* {{{ */
if (!PS(id) || !ZSTR_VAL(PS(id))[0]) {
if (PS(id)) {
zend_string_release_ex(PS(id), 0);
+ PS(id) = NULL;
}
PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
if (!PS(id)) {
@@ -460,6 +461,7 @@ static zend_result php_session_initialize(void) /* {{{ */
) {
if (PS(id)) {
zend_string_release_ex(PS(id), 0);
+ PS(id) = NULL;
}
PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
if (!PS(id)) {
@@ -2440,6 +2442,7 @@ PHP_FUNCTION(session_regenerate_id)
/* Try to generate non-existing ID */
while (limit-- && PS(mod)->s_validate_sid(&PS(mod_data), PS(id)) == SUCCESS) {
zend_string_release_ex(PS(id), 0);
+ PS(id) = NULL;
PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
if (!PS(id)) {
PS(mod)->s_close(&PS(mod_data));
diff --git a/ext/session/tests/user_session_module/gh23043.phpt b/ext/session/tests/user_session_module/gh23043.phpt
new file mode 100644
index 000000000000..e3528884a79a
--- /dev/null
+++ b/ext/session/tests/user_session_module/gh23043.phpt
@@ -0,0 +1,35 @@
+--TEST--
+GH-23043 (broken session id code can cause zend_mm_heap corrupted)
+--EXTENSIONS--
+session
+--CREDITS--
+lmaltsis
+--FILE--
+
+--EXPECTF--
+string(0) ""
+
+Warning: SessionHandler::write(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed in %s on line %d
+
+Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: a::write) in %s on line %d
+string(0) ""
+
+Warning: SessionHandler::write(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed in Unknown on line 0
+
+Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: a::write) in Unknown on line 0
diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
index 8cf8e657e58f..2976885f6043 100644
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@ -134,7 +134,7 @@ static xmlNodePtr sxe_get_element_by_offset(php_sxe_object *sxe, zend_long offse
return NULL;
}
}
- while (node && nodendx <= offset) {
+ while (node && (offset < 0 || nodendx <= offset)) {
if (node->type == XML_ELEMENT_NODE && match_ns(node, sxe->iter.nsprefix, sxe->iter.isprefix)) {
if (sxe->iter.type == SXE_ITER_CHILD || (
sxe->iter.type == SXE_ITER_ELEMENT && xmlStrEqual(node->name, BAD_CAST ZSTR_VAL(sxe->iter.name)))) {
@@ -319,11 +319,13 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements,
if (node) {
node_as_zval(sxe, node, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix);
} else if (type == BP_VAR_W || type == BP_VAR_RW) {
- if (member && cnt < Z_LVAL_P(member)) {
+ if (member && (Z_LVAL_P(member) < 0 || cnt < Z_LVAL_P(member))) {
php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only " ZEND_LONG_FMT " such elements exist", mynode->name, Z_LVAL_P(member), cnt);
}
- node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL);
- node_as_zval(sxe, node, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix);
+ if (!member || Z_LVAL_P(member) >= 0) {
+ node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL);
+ node_as_zval(sxe, node, rv, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix);
+ }
}
} else {
/* In BP_VAR_IS mode only return a proper node if it actually exists. */
@@ -586,10 +588,14 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value,
newnode = xmlNewTextChild(mynode, NULL, (xmlChar *)Z_STRVAL_P(member), value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL);
}
} else if (!member || Z_TYPE_P(member) == IS_LONG) {
- if (member && cnt < Z_LVAL_P(member)) {
+ if (member && (Z_LVAL_P(member) < 0 || cnt < Z_LVAL_P(member))) {
php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only " ZEND_LONG_FMT " such elements exist", mynode->name, Z_LVAL_P(member), cnt);
}
- newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL);
+ if (member && Z_LVAL_P(member) < 0) {
+ value = &EG(error_zval);
+ } else {
+ newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value_str ? (xmlChar *)ZSTR_VAL(value_str) : NULL);
+ }
}
} else if (attribs) {
if (Z_TYPE_P(member) == IS_LONG) {
diff --git a/ext/simplexml/tests/bug_sxe_negative_offset.phpt b/ext/simplexml/tests/bug_sxe_negative_offset.phpt
new file mode 100644
index 000000000000..5df3cb2548e2
--- /dev/null
+++ b/ext/simplexml/tests/bug_sxe_negative_offset.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Negative SimpleXML element offsets must not alias the first element
+--EXTENSIONS--
+simplexml
+--FILE--
+- a
- b
- c
');
+$items = $xml->item;
+
+echo "isset[-1]: ";
+var_dump(isset($items[-1]));
+echo "read[-1]: ";
+var_dump($items[-1]);
+echo "read[0]: ";
+var_dump((string)$items[0]);
+
+$items[-1] = 'Z';
+echo "after negative write: ", $xml->asXML();
+
+$items[5] = 'P';
+echo "after out-of-range write: ", $xml->asXML();
+?>
+--EXPECTF--
+isset[-1]: bool(false)
+read[-1]: NULL
+read[0]: string(1) "a"
+
+Warning: main(): Cannot add element item number -1 when only 3 such elements exist in %s on line %d
+after negative write:
+- a
- b
- c
+
+Warning: main(): Cannot add element item number 5 when only 3 such elements exist in %s on line %d
+after out-of-range write:
+- a
- b
- c
- P
diff --git a/ext/standard/tests/mail/bug80751.phpt b/ext/standard/tests/mail/bug80751.phpt
index b6dc29e42f14..802bd542482d 100644
--- a/ext/standard/tests/mail/bug80751.phpt
+++ b/ext/standard/tests/mail/bug80751.phpt
@@ -48,7 +48,7 @@ foreach (['to' => $to, 'cc' => $cc, 'bcc' => $bcc] as $recipient => $mailAddress
echo "Found the email. {$recipient} received.\n";
}
- if ($mail->getHeader('Return-Path') === $from) {
+ if ($mail->getHeader('Return-Path') === "<{$from}>") {
echo "Return-Path is as expected.\n";
}