[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5

Weilin Du <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Weilin Du (LamentXU123)
Date: 2026-07-10T16:50:49+08:00

Commit: https://github.com/php/php-src/commit/b686856390149cce73dd90f57840c17df0d61913
Raw diff: https://github.com/php/php-src/commit/b686856390149cce73dd90f57840c17df0d61913.diff

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  Fix GH-22649: avoid ZipArchive comment reset crash (#22652)

Changed paths:
  A  ext/zip/tests/gh22649.phpt
  M  NEWS
  M  ext/zip/php_zip.c


Diff:

diff --git a/NEWS b/NEWS
index f337403fbebe..d28381c3902b 100644
--- a/NEWS
+++ b/NEWS
@@ -102,6 +102,9 @@ PHP                                                                        NEWS
     opaque hosts. (kocsismate)
 
 - Zip:
+  . Fixed bug GH-22649 (ZipArchive::setCommentName() and setCommentIndex()
+    could crash after overwriting an entry and resetting its inherited
+    unchanged comment). (Weilin Du)
   . Fixed bug GH-21705 (ZipArchive::getFromIndex() ignores
     ZipArchive::FL_UNCHANGED for deleted entries). (Weilin Du)
 
diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c
index fd339e4fe745..fbb8594013a4 100644
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@ -58,17 +58,26 @@ static int le_zip_entry;
 	}
 /* }}} */
 
-/* {{{ PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) */
-#define PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) \
-	if (comment_len == 0) { \
-		/* Passing NULL remove the existing comment */ \
-		if (zip_file_set_comment(za, index, NULL, 0, 0) < 0) { \
-			RETURN_FALSE; \
-		} \
-	} else if (zip_file_set_comment(za, index, comment, comment_len, 0) < 0) { \
-		RETURN_FALSE; \
-	} \
-	RETURN_TRUE;
+/* {{{ php_zip_set_file_comment */
+static bool php_zip_set_file_comment(struct zip *za, zip_uint64_t index, const char *comment, size_t comment_len)
+{
+	zip_uint32_t current_comment_len;
+	const char *current_comment = zip_file_get_comment(za, index, &current_comment_len, ZIP_FL_ENC_RAW);
+
+	/* Avoid a libzip use-after-free when resetting an unchanged inherited comment. */
+	if (current_comment && current_comment_len == comment_len
+			&& memcmp(current_comment, comment, comment_len) == 0) {
+		return true;
+	}
+
+	if (comment_len == 0) {
+		/* Passing NULL removes the existing comment. */
+		return zip_file_set_comment(za, index, NULL, 0, 0) == 0;
+	}
+
+	ZEND_ASSERT(comment_len <= 0xffff);
+	return zip_file_set_comment(za, index, comment, (zip_uint16_t) comment_len, 0) == 0;
+}
 /* }}} */
 
 # define add_ascii_assoc_string add_assoc_string
@@ -2137,7 +2146,7 @@ PHP_METHOD(ZipArchive, setCommentName)
 	zval *self = ZEND_THIS;
 	size_t comment_len, name_len;
 	char * comment, *name;
-	int idx;
+	zip_int64_t idx;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
 			&name, &name_len, &comment, &comment_len) == FAILURE) {
@@ -2160,7 +2169,7 @@ PHP_METHOD(ZipArchive, setCommentName)
 	if (idx < 0) {
 		RETURN_FALSE;
 	}
-	PHP_ZIP_SET_FILE_COMMENT(intern, idx, comment, comment_len);
+	RETURN_BOOL(php_zip_set_file_comment(intern, (zip_uint64_t) idx, comment, comment_len));
 }
 /* }}} */
 
@@ -2173,6 +2182,7 @@ PHP_METHOD(ZipArchive, setCommentIndex)
 	size_t comment_len;
 	char * comment;
 	struct zip_stat sb;
+	zip_uint64_t idx;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls",
 			&index, &comment, &comment_len) == FAILURE) {
@@ -2187,7 +2197,9 @@ PHP_METHOD(ZipArchive, setCommentIndex)
 	}
 
 	PHP_ZIP_STAT_INDEX(intern, index, 0, sb);
-	PHP_ZIP_SET_FILE_COMMENT(intern, index, comment, comment_len);
+	idx = (zip_uint64_t) index;
+
+	RETURN_BOOL(php_zip_set_file_comment(intern, idx, comment, comment_len));
 }
 /* }}} */
 
diff --git a/ext/zip/tests/gh22649.phpt b/ext/zip/tests/gh22649.phpt
new file mode 100644
index 000000000000..d6d0a0928184
--- /dev/null
+++ b/ext/zip/tests/gh22649.phpt
@@ -0,0 +1,55 @@
+--TEST--
+GH-22649 (setCommentName/Index after addFromString should not segfault)
+--EXTENSIONS--
+zip
+--FILE--
+<?php
+$file = __DIR__ . '/gh22649.zip';
+
+@unlink($file);
+
+$zip = new ZipArchive;
+if (!$zip->open($file, ZipArchive::CREATE)) {
+    exit('failed');
+}
+
+$zip->addFromString('dir/entry2d.txt', 'entry #2');
+var_dump($zip->setCommentName('dir/entry2d.txt', 'dir/entry2d.txt'));
+
+$zip->addFromString('dir/entry3d.txt', 'entry #3');
+var_dump($zip->setCommentIndex($zip->lastId, 'dir/entry3d.txt'));
+
+$zip->close();
+
+if (!$zip->open($file, ZipArchive::CREATE)) {
+    exit('failed');
+}
+
+$zip->addFromString('dir/entry2d.txt', 'updated entry #2');
+var_dump($zip->setCommentName('dir/entry2d.txt', 'dir/entry2d.txt'));
+
+$zip->addFromString('dir/entry3d.txt', 'updated entry #3');
+var_dump($zip->setCommentIndex($zip->lastId, 'dir/entry3d.txt'));
+
+$zip->close();
+
+if (!$zip->open($file)) {
+    exit('failed');
+}
+
+var_dump($zip->getCommentName('dir/entry2d.txt'));
+var_dump($zip->getCommentName('dir/entry3d.txt'));
+
+$zip->close();
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+string(15) "dir/entry2d.txt"
+string(15) "dir/entry3d.txt"
+--CLEAN--
+<?php
+@unlink(__DIR__ . '/gh22649.zip');
+?>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.