Commit 1f1147a6663 for php.net

commit 1f1147a66633f5a3ef11d3ab8429a6e3695c68f2
Author: David Carlier <devnexen@gmail.com>
Date:   Sat Nov 29 21:32:19 2025 +0000

    Fix GH-20620: bzcompress() overflow on large source size.

    close GH-20621

diff --git a/NEWS b/NEWS
index d6b832917df..472f57a38f6 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? ????, PHP 8.3.30

+- Bz2:
+  . Fixed bug GH-20620 (bzcompress overflow on large source size).
+    (David Carlier)
+
 - GD:
   . Fixed bug GH-20622 (imagestring/imagestringup overflow). (David Carlier)

diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c
index 7f546f95cd0..060a2df6400 100644
--- a/ext/bz2/bz2.c
+++ b/ext/bz2/bz2.c
@@ -459,7 +459,15 @@ PHP_FUNCTION(bzcompress)
 	   + .01 x length of data + 600 which is the largest size the results of the compression
 	   could possibly be, at least that's what the libbz2 docs say (thanks to jeremy@nirvani.net
 	   for pointing this out).  */
-	dest_len = (unsigned int) (source_len + (0.01 * source_len) + 600);
+	size_t chunk_len = source_len + source_len / 100 + 600;
+	const size_t min = MIN(ZSTR_MAX_LEN, UINT_MAX);
+
+	if (chunk_len < source_len || chunk_len > min) {
+		zend_argument_value_error(1, "must have a length less than or equal to %zu", min);
+		RETURN_THROWS();
+	}
+
+	dest_len = (unsigned int) chunk_len;

 	/* Allocate the destination buffer */
 	dest = zend_string_alloc(dest_len, 0);
diff --git a/ext/bz2/tests/gh20620.phpt b/ext/bz2/tests/gh20620.phpt
new file mode 100644
index 00000000000..351ba488b2b
--- /dev/null
+++ b/ext/bz2/tests/gh20620.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Bug GH-20620 (bzcompress with large source)
+--EXTENSIONS--
+bz2
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE != 8) die('skip this test is for 64bit platforms only');
+if (getenv('SKIP_SLOW_TESTS')) die('skip slow tests excluded by request');
+?>
+--INI--
+memory_limit=-1
+--FILE--
+<?php
+try {
+	bzcompress(str_repeat('1', 4295163906));
+} catch (\ValueError $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+?>
+--EXPECTF--
+bzcompress(): Argument #1 ($data) must have a length less than or equal to %d