Commit 15d58caa797 for php.net
commit 15d58caa79753525f70e100ce25a468a7c7b8fca
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Thu Jun 25 09:18:44 2026 -0400
Fix unsigned wrap in bzdecompress() output realloc at source_len UINT_MAX (#22432)
The input guard rejects only source_len > UINT_MAX, so source_len ==
UINT_MAX is permitted and assigned to bzs.avail_out (unsigned int). The
per-iteration realloc then computed bzs.avail_out+1 in unsigned int
arithmetic, which wraps to 0 at UINT_MAX, allocating no headroom while
bz2 still believes avail_out bytes are available at next_out: the next
decompress round writes past the buffer. Compute the term as
(size_t)bzs.avail_out + 1 so the increment is done in size_t and cannot
wrap, matching the (size_t) casts already used on the same call.
diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c
index 512632fe8a2..6af8286c533 100644
--- a/ext/bz2/bz2.c
+++ b/ext/bz2/bz2.c
@@ -544,7 +544,7 @@ PHP_FUNCTION(bzdecompress)
/* no reason to continue if we're going to drop it anyway */
break;
}
- dest = zend_string_safe_realloc(dest, 1, bzs.avail_out+1, (size_t) size, 0);
+ dest = zend_string_safe_realloc(dest, 1, (size_t) bzs.avail_out + 1, (size_t) size, 0);
bzs.next_out = ZSTR_VAL(dest) + size;
}